llist 42777 241 0 0 11531264353 7344 5 ustar 00IUSR0001 llist/llist.rpgle 100700 241 0 300570 11542211164 11724 0 ustar 00IUSR0001 /**
* \brief Linked List Implementation
*
* This is a typical Doubly-Linked List (Two-Way Linked List) Implementation
* using dynamic memory allocation. The list is particular suitable for
* character values but does also work with any other data (f. e. data
* structures).
*
*
*
* Values are stored as null-terminated chars.
*
*
*
* Operations that index into the list will traverse the list from
* the beginning or the end, whichever is closer to the specified index.
*
*
*
* Iteration: With the procedure getNext the list is
* traversable in the top-bottom direction. Each call to getNext
* will return the next entry of the list till the end of the list.
* If the walk through the list should be stopped early (before the end
* of the list) the method abortIteration should be called.
* If the list is structurally modified at any time
* after an iteration has begun in any way, the result of the iteration
* can not be safely determined. If an iteratioj is not going to continue
* the procedure abortIteration should be called. After that
* call it is safe to modify the list again.
*
*
*
* Throughout this service program a zero-based index is used.
*
*
*
* This list implementation is not thread-safe.
*
* \author Mihael Schmidt
* \date 20.12.2007
*
* \rev 22.11.2009 Mihael Schmidt
* Added sorting support
* Changed memory management to user created heap
* Added removeRange procedure
* Bug fix: list_addAll does not work if value has x'00'
*
* \rev 15.12.2009 Mihael Schmidx
* Added merge procedure
*
* \rev 19.02.2011 Mihael Schmidt
* Fixed list_sublist procedure
* Added list_resetIteration
* Deprecated list_abortIteration
* Added list_iterate
* Deprecated list_getNext
* Userdata parameter on list_foreach is now optional
* list_merge got new parameter to only optionally skip duplicate entries
*/
*------------------------------------------------------------------------
*
* Copyright (c) 2007-2009 Mihael Schmidt
* All rights reserved.
*
* This file is part of the LLIST service program.
*
* LLIST is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* LLIST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with LLIST. If not, see http://www.gnu.org/licenses/.
*
*------------------------------------------------------------------------
H NOMAIN
H COPYRIGHT('Copyright (c) 2007-2011 Mihael Schmidt. All rights reserved.')
*-------------------------------------------------------------------------
* Prototypen
*-------------------------------------------------------------------------
/copy 'llist_h.rpgle'
/copy 'llist_in_h.rpgle'
/copy 'ceeapi_h.rpgle'
*-------------------------------------------------------------------------
* Procedures
*-------------------------------------------------------------------------
/**
* \brief Create list
*
* Creates a list. A header is generated for the list and the pointer to
* the list returned.
*
*
*
* A list must be disposed via the procedure dispose to free all
* allocated memory.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \return Pointer to the list
*/
P list_create B export
D PI *
*
D listPtr S *
D header DS likeds(tmpl_header) based(listPtr)
D heapId S 10I 0
/free
cee_createHeap(heapId : *omit : *omit : *omit : *omit);
// allocate memory for list header
cee_getStorage(heapId : %size(tmpl_header) : listPtr : *omit);
header.id = LIST_ID;
header.heapId = heapId;
header.size = 0;
header.bytes = 0;
header.firstEntry = *null;
header.lastEntry = *null;
header.iteration = -1;
header.iterNextEntry = *null;
header.iterPrevEntry = *null;
return listPtr;
/end-free
P E
/**
* \brief Dispose list
*
* The memory for whole list are is released
* (deallocated). The list pointer is set to *null;
*
*
*
* If the passed pointer is already *null the procedure simply returns.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*/
P list_dispose B export
D PI
D listPtr *
D header DS likeds(tmpl_header) based(listPtr)
/free
if (listPtr = *null);
// do nothing
else;
if (isLinkedListImpl(listPtr));
cee_discardHeap(header.heapId : *omit);
listPtr = *null;
endif;
endif;
/end-free
P E
/**
* \brief Add list entry
*
* Adds an entry at an exact position in the list. If the position is
* outside the list the procedure returns *off. The current
* entry of the list at that position will be pushed one position down
* the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
* \param Pointer to the new value
* \param Length of the new value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_add B export
D PI N
D listPtr * const
D ptrValue * const
D length 10U 0 const
D pos 10U 0 const options(*nopass)
*
D header DS likeds(tmpl_header) based(listPtr)
D nextEntryPtr S *
D nextEntry DS likeds(tmpl_entry)
D based(nextEntryPtr)
D prevEntryPtr S *
D prevEntry DS likeds(tmpl_entry)
D based(prevEntryPtr)
D newEntryPtr S *
D newEntry DS likeds(tmpl_entry)
D based(newEntryPtr)
D tmpPtr S *
D retVal S N inz(*on)
/free
if (%parms() = 4);
if (isLinkedListImpl(listPtr));
// check if the position is outside of the list
if (pos < 0 or pos > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
endif;
nextEntryPtr = getListEntryDs(listPtr : pos);
if (nextEntryPtr <> *null);
if (nextEntry.prev <> *null);
prevEntryPtr = nextEntry.prev;
else;
// must be the start of the list (which has no previous entry)
endif;
//
// create new entry
//
// alloc memory for this entry
cee_getStorage(header.heapId:%size(tmpl_entry):newEntryPtr:*omit);
newEntry.length = length + 1; // +1 for the null value
cee_getStorage(header.heapId : length + 1 : newEntry.value :*omit);
newEntry.next = *null;
newEntry.prev = *null;
// copy value to the list entry
memcpy(newEntry.value : ptrValue : length);
// set null to the last byte
tmpPtr = newEntry.value + length;
memcpy(tmpPtr : %addr(hexNull) : 1);
// set pointers so that the list is correctly linked again
newEntry.prev = prevEntryPtr;
newEntry.next = nextEntryPtr;
nextEntry.prev = newEntryPtr;
if (prevEntryPtr <> *null);
prevEntry.next = newEntryPtr;
endif;
// update header
header.size += 1;
if (newEntry.prev = *null);
header.firstEntry = newEntryPtr;
endif;
else;
// could not get entry at given position
retVal = *off;
endif;
else;
retVal = *off;
endif;
else; // append to the end of the list
retVal = list_addLast(listPtr : ptrValue : length);
endif;
return retVal;
/end-free
P E
/**
* \brief Add list entry to the top of the list
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
* \param Pointer to new value
* \param Length of new value
*
* \return *on = successful
* *off = error
*/
P list_addFirst B export
D PI N
D listPtr *
D valuePtr * const
D length 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D newEntryPtr S *
D newEntry DS likeds(tmpl_entry)
D based(newEntryPtr)
D nextEntryPtr S *
D nextEntry DS likeds(tmpl_entry)
D based(nextEntryPtr)
D tmpPtr S *
D retVal S N inz(*on)
/free
if (isLinkedListImpl(listPtr));
//
// create new entry
//
// alloc memory for this entry
cee_getStorage(header.heapId:%size(tmpl_entry):newEntryPtr:*omit);
newEntry.length = length + 1; // +1 for the null value
cee_getStorage(header.heapId : length + 1 : newEntry.value :*omit);
newEntry.next = *null;
newEntry.prev = *null;
// copy value to the list entry
memcpy(newEntry.value : valuePtr : length);
// add null
tmpPtr = newEntry.value + length;
memcpy(tmpPtr : %addr(hexNull) : 1);
if (header.size > 0);
nextEntryPtr = getListEntryDs(listPtr : 0);
nextEntry.prev = newEntryPtr;
newEntry.next = nextEntryPtr;
endif;
// update header
header.size += 1;
header.firstEntry = newEntryPtr;
if (header.size = 1);
header.lastEntry = newEntryPtr;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Add list entry to the end of the list
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
* \param Pointer to new value
* \param Length of new value
*
* \return *on = successful
* *off = error
*/
P list_addLast B export
D PI N
D listPtr * const
D valuePtr * const
D length 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D newEntryPtr S *
D newEntry DS likeds(tmpl_entry)
D based(newEntryPtr)
D prevEntryPtr S *
D prevEntry DS likeds(tmpl_entry)
D based(prevEntryPtr)
D tmpPtr S *
D retVal S N inz(*on)
/free
if (isLinkedListImpl(listPtr));
//
// create new entry
//
// alloc memory for this entry
cee_getStorage(header.heapId:%size(tmpl_entry):newEntryPtr:*omit);
newEntry.length = length + 1; // +1 for the null value
cee_getStorage(header.heapId : length + 1 : newEntry.value :*omit);
newEntry.next = *null;
newEntry.prev = *null;
// copy value to the list entry
memcpy(newEntry.value : valuePtr : length);
// add null
tmpPtr = newEntry.value + length;
memcpy(tmpPtr : %addr(hexNull) : 1);
if (header.size > 0);
prevEntryPtr = getListEntryDs(listPtr : header.size -1);
prevEntry.next = newEntryPtr;
newEntry.prev = prevEntryPtr;
endif;
// update header
header.size += 1;
header.lastEntry = newEntryPtr;
if (header.size = 1);
header.firstEntry = newEntryPtr;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Add all elements of a list
*
* Adds all elements of the passed list to the end of this list.
* Elements will not be referenced but storage newly allocated.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the destination list
* \param Pointer to the source list
*
* \return *on = all elements added to list
* *off = not all or none elements added
*/
P list_addAll B export
D PI N
D listPtr * const
D srcListPtr * const
*
D retVal S N inz(*on)
D header DS likeds(tmpl_header) based(srcListPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
/free
if (isLinkedListImpl(listPtr) and
isLinkedLIstImpl(srcListPtr));
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
// entry.length -1 => dont include the null value
if (not list_add(listPtr : entry.value : entry.length-1));
retVal = *off;
leave;
endif;
entryPtr = entry.next;
enddo;
endif;
return retVal;
/end-free
P E
/**
* \brief Remove list entry
*
* Removes an entry from the list at the given position. If the
* position is outside of the list the return value will be *off.
*
*
*
* The index is 0 (zero) based.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
* \param index of the entry in the list (zero-based)
*
* \return *on = entry removed
* *off = error
*/
P list_remove B export
D PI N
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D ptr S *
D entry DS likeds(tmpl_entry) based(ptr)
D nextEntryPtr S *
D nextEntry DS likeds(tmpl_entry)
D based(nextEntryPtr)
D prevEntryPtr S *
D prevEntry DS likeds(tmpl_entry)
D based(prevEntryPtr)
D retVal S N inz(*on)
/free
if (isLinkedListImpl(listPtr));
// check if the position is outside of the list
if (index < 0 or index > header.size -1);
return *off;
endif;
ptr = getListEntryDs(listPtr : index);
if (ptr = *null);
return *off;
endif;
nextEntryPtr = entry.next;
prevEntryPtr = entry.prev;
if (prevEntryPtr <> *null);
prevEntry.next = nextEntryPtr;
endif;
if (nextEntryPtr <> *null);
nextEntry.prev = prevEntryPtr;
endif;
// free memory
cee_freeStorage(entry.value : *omit);
cee_freeStorage(ptr : *omit);
// update header
header.size -= 1;
if (nextEntryPtr = *null);
header.lastEntry = prevEntryPtr;
endif;
if (prevEntryPtr = *null);
header.firstEntry = nextEntryPtr;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Remove first list entry
*
* Removes the first entry from the list.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \return *on = entry removed
* *off = error
*/
P list_removeFirst...
P B export
D PI N
D listPtr * const
/free
return list_remove(listPtr : 0);
/end-free
P E
/**
* \brief Remove last list entry
*
* Removes the last entry from the list.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \return *on = entry removed
* *off = error (escape message)
*/
P list_removeLast...
P B export
D PI N
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D retVal S N inz(*off)
/free
if (isLinkedListImpl(listPtr));
retVal = list_remove(listPtr : header.size - 1);
endif;
return retVal;
/end-free
P E
/**
* \brief Clear list
*
* Deletes all entries in the list.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \return *on = successful
* *off = error
*/
P list_clear B export
D PI N
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D tmpPtr S *
D ptr S *
D entry DS likeds(tmpl_entry) based(ptr)
D retVal S N inz(*off)
/free
if (isLinkedListImpl(listPtr));
ptr = header.lastEntry;
dow (ptr <> *null);
tmpPtr = entry.prev;
if (entry.value <> *null);
cee_freeStorage(entry.value : *omit);
endif;
cee_freeStorage(ptr : *omit);
ptr = tmpPtr;
enddo;
// update header
header.size = 0;
header.firstEntry = *null;
header.lastEntry = *null;
header.bytes = %size(tmpl_header);
header.iteration = -1;
header.iterNextEntry = *null;
header.iterPrevEntry = *null;
endif;
return retVal;
/end-free
P E
/**
* \brief Get next entry
*
* Iterates through the list and gets the next entry. If the iterator is
* at the end of the list this method will return null. The
* iteration can be aborted early with the procedure
* list_resetIteration.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \return Pointer to entry or *null if no more entries in list
*
* \deprecated Use list_iterate instead.
*/
P list_getNext B export
D PI *
D listPtr * const
*
/free
return list_iterate(listPtr);
/end-free
P E
/**
* \brief Iterate list
*
* Iterates through the list and returns the next entry. If the iterator is
* at the end of the list this method will return null. The
* iteration can be aborted early with the procedure list_resetIteration.
*
* \author Mihael Schmidt
* \date 19.2.2011
*
* \param Pointer to the list
*
* \return Pointer to entry or *nµll if no more entries in list
*/
P list_iterate B export
D PI *
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D retVal S *
/free
if (isLinkedListImpl(listPtr));
if (header.iteration + 1 = header.size);
list_resetIteration(listPtr);
retVal = *null;
else;
header.iteration += 1;
if (header.iterNextEntry = *null);
entryPtr = getListEntryDs(listPtr : header.iteration);
else;
entryPtr = header.iterNextEntry;
endif;
header.iterNextEntry = entry.next;
header.iterPrevEntry = entry.prev;
retVal = entry.value;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Get previous entry
*
* Iterates through the list and gets the previous entry. If the iterator is
* before the start of the list this method will return null. The
* iteration can be aborted early with the procedure list_resetIteration.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \return Pointer to entry or *null if no more entries in list
*/
P list_getPrev B export
D PI *
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D retVal S *
/free
if (isLinkedListImpl(listPtr));
if (header.iteration = 0);
list_resetIteration(listPtr);
retVal = *null;
else;
if (header.iteration = -1);
header.iteration = header.size;
endif;
header.iteration -= 1;
if (header.iterPrevEntry = *null);
entryPtr = getListEntryDs(listPtr : header.iteration);
else;
entryPtr = header.iterPrevEntry;
endif;
if (entryPtr = *null);
retVal = *null;
else;
header.iterNextEntry = entry.next;
header.iterPrevEntry = entry.prev;
retVal = entry.value;
endif;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Abort iteration
*
* If the iteration through the list should be aborted early this
* procedure should be called.
*
* \author Mihael Schmidt
* \date 18.12.2007
*
* \param Pointer to the list
*
* \deprecated Use list_resetIteration instead.
*/
P list_abortIteration...
P B export
D PI
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
/free
list_resetIteration(listPtr);
/end-free
P E
/**
* \brief Reset iteration
*
* Resets the internal iteration state of the list so that the next
* call to list_iterate will return the first element.
*
* \author Mihael Schmidt
* \date 19.2.2011
*
* \param Pointer to the list
*/
P list_resetIteration...
P B export
D PI
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
/free
if (isLinkedListImpl(listPtr));
header.iteration = -1;
header.iterNextEntry = *null;
header.iterPrevEntry = *null;
endif;
/end-free
P E
/**
* \brief Replaces an entry in the list
*
* An element in the list will be replaced. If there is no element
* at that position the return value will be *off.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param Pointer to new value
* \param Length of new value
* \param index of new value
*
* \return *on = entry successfully replaced
* *off = error
*/
P list_replace B export
D PI N
D listPtr * const
D ptrValue * const
D lengthValue 10U 0 const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D retVal S N inz(*on)
/free
if (isLinkedListImpl(listPtr));
// check if the position is outside of the list
if (index < 0 or index > header.size -1);
return *off;
endif;
entryPtr = getListEntryDs(listPtr : index);
entry.length = lengthValue + 1;
cee_reallocateStorage(entry.value : lengthValue + 1 : *omit); // +1 for the null byte
// copy value to the list entry
memcpy(ptrValue : entry.value : lengthValue);
// set null to the last byte
memcpy(entry.value + lengthValue : %addr(hexNull) : 1);
endif;
return retVal;
/end-free
P E
/**
* \brief Contains entry
*
* Checks if this list contains the passed entry.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param Pointer to value
* \param Length of value
*
* \return *on = list contains value
* *off = list does not contain value
*/
P list_contains B export
D PI N
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D retVal S N inz(*off)
/free
if (isLinkedListImpl(listPtr));
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
if (valueLength = entry.length - 1 and
memcmp(valuePtr : entry.value : valueLength) = 0); // dont include the null
retVal = *on;
leave;
endif;
entryPtr = entry.next;
enddo;
endif;
return retVal;
/end-free
P E
/**
* \brief Check if list is empty
*
* Checks if the list is empty.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
*
* \return *on = list is empty
* *off = list is not empty
*/
P list_isEmpty B export
D PI N
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D retVal S N
/free
if (isLinkedListImpl(listPtr));
if (header.size = 0);
retVal = *on;
else;
retVal = *off;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Get entry
*
* Returns a list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param List position
*
* \return Pointer to a null terminated string or
* *null if an error occured or there is no
* entry at that position
*/
P list_get B export
D PI *
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D retVal S *
D tmp S 1000A based(entry.value)
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
return *null;
elseif (index < 0 or index > header.size -1);
return *null;
endif;
entryPtr = getListEntryDs(listPtr : index);
retVal = entry.value;
endif;
return retVal;
/end-free
P E
/**
* \brief Get first entry
*
* Returns the first entry of the list.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
*
* \return Pointer to a null terminated string or
* *null if the list is empty or an error occured
*/
P list_getFirst B export
D PI *
D listPtr * const
*
D retVal S * inz(*null)
/free
if (isLinkedListImpl(listPtr));
retVal = list_get(listPtr : 0);
endif;
return retVal;
/end-free
P E
/**
* \brief Get last entry
*
* Returns the last entry of the list.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
*
* \return Pointer to a null terminated string or
* *null if the list is empty or an error occured
*/
P list_getLast B export
D PI *
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D retVal S * inz(*null)
/free
if (isLinkedListImpl(listPtr));
retVal = list_get(listPtr : header.size -1);
endif;
return retVal;
/end-free
P E
/**
* \brief Index of entry
*
* Returns the index of the passed entry or -1 if the entry could not
* be found in the list.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param Pointer to the value
* \param Length of the value
*
* \return index of the entry or -1 if entry not in list
*/
P list_indexOf B export
D PI 10I 0
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D i S 10I 0 inz(-1)
D retVal S 10I 0 inz(-1)
/free
if (isLinkedListImpl(listPtr));
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
i += 1;
if (valueLength = entry.length - 1 and
memcmp(valuePtr : entry.value : valueLength) = 0); // dont include the null
retVal = i;
leave;
endif;
entryPtr = entry.next;
enddo;
endif;
return retVal;
/end-free
P E
/**
* \brief Last index of entry
*
* Returns the last indes of the passed entry or -1 if the entry
* could not be found in the list.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param Pointer to the value
* \param Length of the value
*
* \return index of the entry or -1 if entry not in list
*/
P list_lastIndexOf...
P B export
D PI 10I 0
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D i S 10I 0
D retVal S 10I 0 inz(-1)
/free
if (isLinkedListImpl(listPtr));
entryPtr = header.lastEntry;
i = header.size;
dow (entryPtr <> *null);
i -= 1;
if (valueLength = entry.length - 1 and
memcmp(valuePtr : entry.value : valueLength) = 0); // dont include the null
retVal = i;
leave;
endif;
entryPtr = entry.prev;
enddo;
endif;
return retVal;
/end-free
P E
/**
* \brief To character array
*
* Copies all entries of this list to the passed array. Entries will be
* truncated if they are too big for the array. If the array is not big
* enough, the last entries will be silently dropped.
*
* \author Mihael Schmidt
* \date 19.12.2007
*
* \param Pointer to the list
* \param Pointer to the array
* \param Element count
* \param Element length
*
*/
P list_toCharArray...
P B export
D PI
D listPtr * const
D arrayPtr * const
D count 10U 0 const
D length 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D i S 10I 0
D arrayElemPtr S *
D tmpLength S 10I 0
/free
if (isLinkedListImpl(listPtr));
if (header.size = 0);
return;
endif;
for i = 0 to header.size;
if (count > i);
entryPtr = getListEntryDs(listPtr : i);
arrayElemPtr = arrayPtr + (i * length);
if (entry.length < length);
tmpLength = entry.length;
else;
tmpLength = length;
endif;
memcpy(arrayElemPtr : entry.value : tmpLength);
endif;
endfor;
endif;
/end-free
P E
/**
* \brief Check for linked list implementation
*
* Checks if the pointer points to a linked list implementation.
* The linked list implementation of this service program has
* an id in the first 20 bytes of the list header.
*
*
*
* If the pointer does not point to a list implementation an
* escape message will be sent.
*
* \author Mihael Schmidt
* \date 23.12.2007
*
* \param Pointer to the list
*
* \return *on = is linked list implementation
* *off = is no linked list implementation (escape message)
*/
P isLinkedListImpl...
P B export
D PI N
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D isList S N
/free
monitor;
if (header.id = LIST_ID);
isList = *on;
else;
isList = *off;
endif;
on-error *all;
isList = *off;
endmon;
if (not isList);
sendEscapeMessage(MSG_NO_LIST_IMPL);
endif;
return isList;
/end-free
P E
/**
* \brief Send Escape Message
*
* Sends an escape message with the specified id.
*
* \author Mihael Schmidt
* \date 23.12.2007
*
* \param Message id
*/
P sendEscapeMessage...
P B export
D PI
D id 10I 0 const
*
D sendProgramMessage...
D PR extpgm('QMHSNDPM')
D szMsgID 7A const
D szMsgFile 20A const
D szMsgData 6000A const options(*varsize)
D nMsgDataLen 10I 0 const
D szMsgType 10A const
D szCallStkEntry...
D 10A const
D nRelativeCallStkEntry...
D 10I 0 const
D szRtnMsgKey 4A
D error 265A options(*varsize)
*
D msgdata S 512A
D msgkey S 4A
D apiError S 265A
/free
if (id = MSG_NO_LIST_IMPL);
msgdata = 'The pointer does not point to a list data structure.';
elseif (id = MSG_POSITION_OUT_OF_BOUNDS);
msgdata = 'The index points outside the list. No such element in ' +
'the list.';
elseif (id = MSG_INVALID_VALUE_TYPE);
msgdata = 'The requested type does not correspond to the list ' +
'entry type.';
endif;
sendProgramMessage('CPF9898' :
'QCPFMSG *LIBL ' :
%trimr(msgdata) :
%len(%trimr(msgdata)) :
'*ESCAPE ' :
'*PGMBDY' :
0 :
msgkey :
apiError);
/end-free
P E
/**
* \brief Get list entry data structure
*
* Returns the data structure of a list entry.
*
* \author Mihael Schmidt
* \date 23.12.2007
*
* \param Pointer to the list
* \param List position (zero-based)
*
* \return Pointer to list entry or *null
*/
P getListEntryDs...
P B export
D PI *
D listPtr * const
D pos 10I 0 const
*
D i S 10I 0
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
/free
monitor;
if (pos < header.size / 2);
// walk through the list from the start to the end
entryPtr = header.firstEntry;
for i = 0 to pos-1;
if (entryPtr = *null);
leave;
endif;
entryPtr = entry.next;
endfor;
else;
// walk through the list from the end to the start
entryPtr = header.lastEntry;
for i = header.size -1 downto pos + 1;
if (entryPtr = *null);
leave;
endif;
entryPtr = entry.prev;
endfor;
endif;
on-error *all;
entryPtr = *null;
endmon;
return entryPtr;
/end-free
P E
/**
* \brief Get list size
*
* Returns the number elements in the list.
*
* \author Mihael Schmidt
* \date 16.01.2008
*
* \param Pointer to the list
*
* \return number of elements in the list or -1 if an error occurs
*/
P list_size B export
D PI 10U 0
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
/free
if (isLinkedListImpl(listPtr));
return header.size;
else;
return -1;
endif;
/end-free
P E
/**
* \brief Create sublist
*
* Creates a list with copies of a part of the passed list.
*
* \author Mihael Schmidt
* \date 16.1.2008
*
* \param Pointer to the list
* \param start of the index to copy
* \param number of elements to copy
*
* \return new list
*/
P list_sublist B export
D PI *
D listPtr * const
D startIndex 10U 0 const
D length 10U 0 const options(*nopass)
*
D header DS likeds(tmpl_header) based(listPtr)
D entry DS likeds(tmpl_entry) based(entryPtr)
D newListPtr S *
D i S 10I 0
D endIndex S 10I 0
/free
if (isLinkedListImpl(listPtr));
if (%parms() = 2);
endIndex = header.size -1;
else;
endIndex = startIndex + length - 1;
endif;
if (startIndex < 0);
return *null;
endif;
newListPtr = list_create();
entryPtr = getListEntryDs(listPtr : startIndex);
for i = startIndex to endIndex;
if (header.size > i);
list_add(newListPtr : entry.value : entry.length - 1);
entryPtr = entry.next;
else;
leave;
endif;
endfor;
return newListPtr;
else;
return *null;
endif;
/end-free
P E
/**
* \brief Rotate list by n positions
*
* Rotatas items in the list by the given number.
*
*
*
* The elements from the end will be pushed to the front.
* A rotation of one will bring the last element to the first
* position and the first element will become the second element
* (pushed one position down the list).
*
*
*
* Only a forward rotation is possible. No negative number of
* rotations are valid.
*
*
*
* The number of rotations may even be greater than the size of
* the list. Example: List size 4, rotation number 5 = rotation
* number 1.
*
* \author Mihael Schmidt
* \date 23.01.2008
*
ą * \param Pointer to the list
* \param Number positions to rotate list
*/
P list_rotate B export
D PI
D listPtr * const
D rotatePos 10I 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D newStartPtr S *
D newStartEntry DS likeds(tmpl_entry) based(newStartPtr)
D newEndPtr S *
D newEndEntry DS likeds(tmpl_entry) based(newEndPtr)
D firstPtr S *
D firstEntry DS likeds(tmpl_entry) based(firstPtr)
D lastPtr S *
D lastEntry DS likeds(tmpl_entry) based(lastPtr)
D absRotPos S 10I 0
/free
if (isLinkedListImpl(listPtr));
if (header.size = 0);
return;
endif;
absRotPos = %rem(rotatePos : list_size(listPtr));
if (absRotPos > 0);
firstPtr = header.firstEntry;
lastPtr = header.lastEntry;
// connect the ends of the list
firstEntry.prev = lastPtr;
lastEntry.next = firstPtr;
// set new start entry
newStartPtr = getListEntryDs(listPtr :
list_size(listPtr) - absRotPos);
// set new end entry
newEndPtr = newStartEntry.prev;
// disconnect new end and new start entry
newEndEntry.next = *null;
newStartEntry.prev = *null;
// update header
header.firstEntry = newStartPtr;
header.lastEntry = newEndPtr;
endif;
endif;
/end-free
P E
/**
* \brief Swap list items
*
*
* \author Mihael Schmidt
* \date 23.01.2008
*
* \param Pointer to the list
* \param List item to swap
* \param List item to swap
*/
P list_swap B export
D PI N
D listPtr * const
D itemPos1 10U 0 const
D itemPos2 10U 0 const
/free
if (isLinkedListImpl(listPtr));
return internal_swap(listPtr : itemPos1 : itemPos2);
else;
return *off;
endif;
/end-free
P E
P internal_swap B export
D PI N
D listPtr * const
D itemPos1 10U 0 const options(*omit)
D itemPos2 10U 0 const options(*omit)
D itemPtr1 * const options(*nopass)
D itemPtr2 * const options(*nopass)
*
D header DS likeds(tmpl_header) based(listPtr)
*
D entryPtr1 S *
D entry1 DS likeds(tmpl_entry) based(entryPtr1)
D entryPtr1P S *
D entry1P DS likeds(tmpl_entry) based(entryPtr1P)
D entryPtr1N S *
D entry1N DS likeds(tmpl_entry) based(entryPtr1N)
*
D entryPtr2 S *
D entry2 DS likeds(tmpl_entry) based(entryPtr2)
D entryPtr2P S *
D entry2P DS likeds(tmpl_entry) based(entryPtr2P)
D entryPtr2N S *
D entry2N DS likeds(tmpl_entry) based(entryPtr2N)
*
D tmpPtr S *
/free
if (%parms() = 3);
// check both items point to the same entry
if (itemPos1 = itemPos2);
return *on;
endif;
// check if item is out of bounds
if (itemPos1 < 0 or
itemPos2 < 0 or
itemPos1 >= header.size or
itemPos2 >= header.size);
return *off;
endif;
entryPtr1 = getListEntryDs(listPtr : itemPos1);
entryPtr2 = getListEntryDs(listPtr : itemPos2);
elseif (%parms() = 5);
entryPtr1 = itemPtr1;
entryPtr2 = itemPtr2;
else;
return *off;
endif;
// check if the entries are valid
if (entryPtr1 <> *null and entryPtr2 <> *null);
entryPtr1P = entry1.prev;
entryPtr1N = entry1.next;
entryPtr2P = entry2.prev;
entryPtr2N = entry2.next;
// check if the two nodes are neighbouring nodes
if (entry1.next = entryPtr2);
entry1.next = entry2.next;
entry2.next = entryPtr1;
entry2.prev = entry1.prev;
entry1.prev = entryPtr2;
if (entryPtr1P <> *null);
entry1P.next = entryPtr2;
endif;
if (entryPtr2N <> *null);
entry2N.prev = entryPtr1;
endif;
elseif (entry1.prev = entryPtr2); // neighbouring nodes (other way round)
entry2.next = entry1.next;
entry1.next = entryPtr2;
entry1.prev = entry2.prev;
entry2.prev = entryPtr1;
if (entryPtr1N <> *null);
entry1N.prev = entryPtr2;
endif;
if (entryPtr2P <> *null);
entry2P.next = entryPtr1;
endif;
else; // no neighbours
tmpPtr = entry1.next;
entry1.next = entry2.next;
entry2.next = tmpPtr;
tmpPtr = entry1.prev;
entry1.prev = entry2.prev;
entry2.prev = tmpPtr;
if (entryPtr1P <> *null);
entry1P.next = entryPtr2;
endif;
if (entryPtr1N <> *null);
entry1N.prev = entryPtr2;
endif;
if (entryPtr2P <> *null);
entry2P.next = entryPtr1;
endif;
if (entryPtr2N <> *null);
entry2N.prev = entryPtr1;
endif;
endif;
if (entry1.prev = *null); // check if it is the first item
header.firstEntry = entryPtr1;
endif;
if (entry2.prev = *null); // check if it is the first item
header.firstEntry = entryPtr2;
endif;
if (entry1.next = *null); // check if it is the last item
header.lastEntry = entryPtr1;
endif;
if (entry2.next = *null); // check if it is the last item
header.lastEntry = entryPtr2;
endif;
return *on;
else;
return *off;
endif;
/end-free
P E
/**
* \brief Execute procedure for every list item
*
* The passed procedure will be executed for every item
* in the list.
*
*
*
* The user can pass data through a pointer to the procedure.
* The pointer will not be touched by this procedure itself, so it
* can be *null.
*
*
*
* The value of list entry can be changed through the passed procedure
* but not the size of the entry/allocated memory.
*
* \author Mihael Schmidt
* \date 23.01.2008
*
* \param Pointer to the list
* \param Procedure pointer
* \param Pointer to user data (optional)
*/
P list_foreach...
P B export
D PI
D listPtr * const
D procPtr * const procptr
D userData * const options(*nopass)
*
D foreachProc PR extproc(procPtr)
D valuePtr * const
D userData * const options(*nopass)
*
D header DS likeds(tmpl_header) based(listPtr)
D ptr S *
D entry DS likeds(tmpl_entry) based(ptr)
D userDataPassed S N
/free
userDataPassed = (%parms() = 3);
if (isLinkedListImpl(listPtr));
ptr = header.firstEntry;
dow (ptr <> *null);
if (userDataPassed);
foreachProc(entry.value : userData);
else;
foreachProc(entry.value);
endif;
ptr = entry.next;
enddo;
endif;
/end-free
P E
/**
* \brief Return character representation of list
*
* Returns a string with the list items separated either by
* the passed or default separator. The items can be
* enclosed by a passed character. The maximum character length
* returned is 65535. Every character/item after that will be
* dropped silently. Items will not be trimmed for this operation.
*
*
*
* If the third parameter is passed, the third parameter will be
* pre- and appended to the item. If the fourth parameter is also
* passed the third parameter will be prepended to the item and the
* fourth parameter will be appended to the item.
*
* \author Mihael Schmidt
* \date 08.02.2008
*
* \param Pointer to the list
* \param separator (default: ,)
* \param enclosing character (default: nothing)
* \param enclosing character at the end of item (default: nothing)
*
* \return character representation of all list items
*/
P list_toString B export
D PI 65535A varying
D listPtr * const
D pSeparator 1A const varying options(*omit:*nopass)
D pEnclosing 100A const varying options(*nopass)
D pEnclosingEnd...
D 100A const varying options(*nopass)
*
D noSeparator S n inz(*off)
D separator S 1A inz(',')
D enclosingStart...
D S 100A varying
D enclosingEnd...
D S 100A varying
D valuePtr S *
D retVal S 65535A varying
/free
if (isLinkedListImpl(listPtr));
// check if separator is passed
if (%parms() >= 2 and %addr(pSeparator) <> *null);
noSeparator = (%len(pSeparator) = 0);
separator = pSeparator;
endif;
// check if enclosing characters are passed
if (%parms() >= 3);
enclosingStart = pEnclosing;
enclosingEnd = pEnclosing;
endif;
// check if we should use different chars for start and end of item
if (%parms() = 4);
enclosingEnd = pEnclosingEnd;
endif;
// process list items
valuePtr = list_getNext(listPtr);
dow (valuePtr <> *null);
if (noSeparator);
retVal += enclosingStart + %str(valuePtr) + enclosingEnd;
else;
retVal += enclosingStart + %str(valuePtr) + enclosingEnd +
separator;
endif;
valuePtr = list_getNext(listPtr);
enddo;
// remove the last separator
if (not noSeparator and %len(retVal) > 0);
%len(retVal) = %len(retVal) -1;
endif;
endif;
return retVal;
/end-free
P E
/**
* \brief Split character string
*
* The passed character string will be split into tokens by either
* a passed or the default separator. All tokens will be added to
* a new list which will be returned.
*
*
*
* Empty (but not blank) values will be dropped silently.
*
* \author Mihael Schmidt
* \date 08.02.2008
*
* \param Character string (null-terminated)
* \param Separator (default: ;)
*
* \return Pointer to the filled list
*/
P list_split B export
D PI * opdesc
D pString 65535A const options(*varsize)
D pSeparator 1A const options(*nopass)
*
D descType S 10I 0
D dataType S 10I 0
D descInfo1 S 10I 0
D descInfo2 S 10I 0
D length S 10I 0
*
D list S *
D token S *
D separator S 1A inz(';')
D string S 65535A inz(*blank)
/free
cee_getOpDescInfo(1 : descType : dataType : descInfo1 : descInfo2 :
length : *omit);
string = %subst(pString : 1 : length);
if (%parms() = 2);
separator = pSeparator;
endif;
list = list_create();
token = getToken(string : separator);
dow (token <> *null);
list_add(list : token : getStringLength(token));
token = getToken(*null : separator);
enddo;
return list;
/end-free
P E
/**
* \brief Reverse list
*
* Reverse the order of the list by simply switching the previous and
* next pointers of each element.
*
* \param Pointer to the list
*/
P list_reverse B export
D PI
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D ptr S *
D entry DS likeds(tmpl_entry) based(ptr)
D tmp S *
/free
ptr = header.lastEntry;
dow (ptr <> *null);
tmp = entry.prev;
entry.prev = entry.next;
entry.next = tmp;
ptr = tmp;
enddo;
// update header
tmp = header.firstEntry;
header.firstEntry = header.lastEntry;
header.lastEntry = tmp;
/end-free
P E
/**
* \brief Create a copy of a list
*
* Creates a list with copies of all elements of the list.
*
* \author Mihael Schmidt
* \date 7.4.2008
*
* \param Pointer to the list
*
* \return Pointer to tše new list
*/
P list_copy B export
D PI *
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D newListPtr S * inz(*null)
/free
if (isLinkedListImpl(listPtr));
newListPtr = list_create();
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
list_add(newListPtr : entry.value : entry.length - 1);
entryPtr = entry.next;
enddo;
return newListPtr;
endif;
return newListPtr;
/end-free
P E
/**
* \brief Frequency of a value in the list
*
* Returns the number of times the passed value
* can be found in the list.
*
* \author Mihael Schmidt
* \date 05.04.2008
*
* \param Pointer to the list
* \param Pointer to the value
* \param Length of the value
*
* \return number of copies of passed value in the list
*/
P list_frequency...
P B export
D PI 10U 0
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D count S 10U 0 inz(0)
/free
if (isLinkedListImpl(listPtr));
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
if (valueLength = entry.length - 1 and
memcmp(valuePtr : entry.value : valueLength) = 0); // dont include the null
count += 1;
endif;
entryPtr = entry.next;
enddo;
endif;
return count;
/end-free
P E
/**
* \brief Add character list entry
*
* Adds a character entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Character value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addString...
P B export
D PI N opdesc
D listPtr * const
D value 65535A const options(*varsize)
D index 10U 0 const options(*nopass)
*
D descType S 10I 0
D dataType S 10I 0
D descInfo1 S 10I 0
D descInfo2 S 10I 0
D length S 10I 0
*
D string S 65535A inz(*blank)
/free
cee_getOpDescInfo(2 : descType : dataType : descInfo1 : descInfo2 :
length : *omit);
string = %subst(value : 1 : length);
if (%parms() = 2);
return list_add(listPtr : %addr(string) : length);
elseif (%parms() = 3);
return list_add(listPtr : %addr(string) : length : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add integer list entry
*
* Adds an integer entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Integer value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addInteger...
P B export
D PI N
D listPtr * const
D value 10I 0 const
D index 10U 0 const options(*nopass)
*
D integer S 10I 0
/free
integer = value;
if (%parms() = 2);
return list_add(listPtr : %addr(integer) : 4);
elseif (%parms() = 3);
return list_add(listPtr : %addr(integer) : 4 : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add long list entry
*
* Adds a long entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Long value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addLong...
P B export
D PI N
D listPtr * const
D value 20I 0 const
D index 10U 0 const options(*nopass)
*
D local S 20I 0
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : 8);
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : 8 : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add short list entry
*
* Adds a short entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Short value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addShort...
P B export
D PI N
D listPtr * const
D value 5I 0 const
D index 10U 0 const options(*nopass)
*
D local S 5I 0
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : 2);
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : 2 : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add float list entry
*
* Adds a float entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Float value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addFloat...
P B export
D PI N
D listPtr * const
D value 4F const
D index 10U 0 const options(*nopass)
*
D local S 4F
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : %size(local));
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : %size(local) : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add double list entry
*
* Adds a double entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Double value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addDouble...
P B export
D PI N
D listPtr * const
D value 8F const
D index 10U 0 const options(*nopass)
*
D local S 8F
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : %size(local));
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : %size(local) : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add boolean list entry
*
* Adds a boolean entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Boolean value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addBoolean...
P B export
D PI N
D listPtr * const
D value N const
D index 10U 0 const options(*nopass)
*
D local S N
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : %size(local));
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : %size(local) : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add packed decimal list entry
*
* Adds a packed decimal entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Packed decimal value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addDecimal...
P B export
D PI N
D listPtr * const
D value 15P 5 const
D index 10U 0 const options(*nopass)
*
D local S 15P 5
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : %size(local));
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : %size(local) : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Add date list entry
*
* Adds a date entry to the list. If the position is outside the list
* the procedure returns *off. The current entry of the list at
* that position will be pushed one position down the list.
*
*
*
* If no position is passed to the procedure then the entry will be
* appended to the end of the list (like addLast).
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param Date value
* \param List position for the new value (optional)
*
* \return *on = entry added the list
* *off = error
*/
P list_addDate...
P B export
D PI N
D listPtr * const
D value D const
D index 10U 0 const options(*nopass)
*
D local S D
/free
local = value;
if (%parms() = 2);
return list_add(listPtr : %addr(local) : %size(local));
elseif (%parms() = 3);
return list_add(listPtr : %addr(local) : %size(local) : index);
else;
return *off;
endif;
/end-free
P E
/**
* \brief Get character entry
*
* Returns a character list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Character string of the specified position
*/
P list_getString...
P B export
D PI 65535A
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 65535A based(entry.value)
D testVar S 65535A
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *blank;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *blank;
endif;
entryPtr = getListEntryDs(listPtr : index);
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = %subst(temp : 1 : entry.length - 1); // subtract the appended null value
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *blank;
endmon;
endif;
/end-free
P E
/**
* \brief Get integer entry
*
* Returns an integer list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Integer value of the specified position
*/
P list_getInteger...
P B export
D PI 10I 0
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 10I 0 based(entry.value)
D testVar S 10I 0
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> 4); // integer = 4 byte
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get short entry
*
* Returns a short list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Short value of the specified position
*/
P list_getShort...
P B export
D PI 5I 0
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 5I 0 based(entry.value)
D testVar S 5I 0
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> 2); // short = 2 byte
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get long entry
*
* Returns a long list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \parem Pointer to the list
* \param List position
*
* \return Long value of the specified position
*/
P list_getLong...
P B export
D PI 20I 0
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 20I 0 based(entry.value)
D testVar S 20I 0
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> 8); // long = 8 byte
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get float entry
*
* Returns a float list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Float value of the specified position
*/
P list_getFloat...
P B export
D PI 4F
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 4F based(entry.value)
D testVar S 4F
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> %size(temp));
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get double entry
*
* Returns a double list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Double value of the specified position
*/
P list_getDouble...
P B export
D PI 8F
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
ąD entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 8F based(entry.value)
D testVar S 8F
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> %size(temp));
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get boolean entry
*
* Returns a boolean list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Boolean value of the specified position
*/
P list_getBoolean...
P B export
D PI N
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S N based(entry.value)
D testVar S N
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> 1);
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get packed decimal entry
*
* Returns a packed decimal list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Packed decimal value of the specified position
*/
P list_getDecimal...
P B export
D PI 15P 5
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S 15P 5 based(entry.value)
D testVar S 15P 5
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> %size(temp));
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Get date entry
*
* Returns a date list entry specified by the passed index.
*
* \author Mihael Schmidt
* \date 21.09.2008
*
* \param Pointer to the list
* \param List position
*
* \return Date value of the specified position
*/
P list_getDate...
P B export
D PI D
D listPtr * const
D index 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
D temp S D based(entry.value)
D testVar S D
/free
if (isLinkedListImpl(listPtr));
// check if list is empty or the position is outside of the list
if (header.size = 0);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
elseif (index < 0 or index > header.size -1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
return *loval;
endif;
entryPtr = getListEntryDs(listPtr : index);
if (entry.length -1 <> %size(temp));
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
endif;
monitor;
// test if the temp variable is filled with the right data for the type
// by moving the data from temp to another var (testVar in this case)
testVar = temp;
return testVar;
on-error *all;
sendEscapeMessage(MSG_INVALID_VALUE_TYPE);
return *loval;
endmon;
endif;
/end-free
P E
/**
* \brief Remove range of elements
*
* Removes a number of elements from the list.
*
* \param Pointer to the list
* \param Starting index
* \param Number of elements to remove
*
* \throws CPF9898 Position out of bounds
*/
P list_removeRange...
P B export
D PI
D listPtr * const
D index 10U 0 const
D pNumberElements...
D 10U 0 const
*
D header DS likeds(tmpl_header) based(listPtr)
D numberElements S 10U 0
D i S 10U 0
/free
isLinkedListImpl(listPtr);
// check if the start is in the range of the list
if (index > header.size - 1);
sendEscapeMessage(MSG_POSITION_OUT_OF_BOUNDS);
endif;
if (index + pNumberElements > header.size -1);
numberElements = header.size - index;
else;
numberElements = pNumberElements;
endif;
for i = 1 to numberElements;
list_remove(listPtr : index);
endfor;
/end-free
P E
/**
* \brief Sort list
*
* Sorts the list with the passed procedure.
*
*
*
* The passed procedure should have the list pointer as its
* only parameter (const) and should sort the list in-place.
*
* \param Pointer to the list
* \param Procedure pointer to the sort procedure
*/
P list_sort B export
D PI
D listPtr * const
D sortAlgorithm...
D * const procptr
*
D sort PR extproc(sortAlgorithm)
D listPtr * const
/free
if (isLinkedListImpl(listPtr));
sort(listPtr);
endif;
/end-free
P E
/**
* \brief Merge lists
*
* Merges the elements of second list with the first list. Elements which
* are already in the first list are not added by default (see third parameter).
*
* \author Mihael Schmidt
* \date 15.12.2009
*
* \param Destination list
* \param Source list
* \param Skip duplicates (default: *off)
*/
P list_merge B export
D PI
D destList * const
D sourceList * const
D pSkipDuplicates...
D N const options(*nopass)
*
D skipDuplicates...
D S N inz(*off)
D header DS likeds(tmpl_header) based(sourceList)
D entryPtr S *
D entry DS likeds(tmpl_entry) based(entryPtr)
/free
if (%parms() = 3);
skipDuplicates = pSkipDuplicates;
endif;
if (isLinkedListImpl(destList) and
isLinkedListImpl(sourceList));
entryPtr = header.firstEntry;
dow (entryPtr <> *null);
if (skipDuplicates);
if (not list_contains(destList : entry.value : entry.length - 1));
list_add(destList : entry.value : entry.length - 1); // dont include the null value
endif;
else;
list_add(destList : entry.value : entry.length - 1); // dont include the null value
endif;
entryPtr = entry.next;
enddo;
endif;
/end-free
P E
llist/llist_h.rpgle 100700 241 0 31026 11535750725 12225 0 ustar 00IUSR0001 /if not defined(LLIST)
/define LLIST
*------------------------------------------------------------------------
*
* Copyright (c) 2007-2011 Mihael Schmidt
* All rights reserved.
*
* This file is part of the LLIST service program.
*
* LLIST is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* LLIST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with LLIST. If not, see http://www.gnu.org/licenses/.
*
*------------------------------------------------------------------------
*-------------------------------------------------------------------------
* Prototypes for Linked List
*-------------------------------------------------------------------------
D list_create PR * extproc('list_create')
*
D list_dispose PR extproc('list_dispose')
D listPtr *
*
D list_add PR N extproc('list_add')
D listPtr * const
D ptrValue * const
D length 10U 0 const
D pos 10U 0 const options(*nopass)
*
D list_addFirst PR N extproc('list_addFirst')
D listPtr *
D valuePtr * const
D length 10U 0 const
*
D list_addLast PR N extproc('list_addLast')
D listPtr * const
D valuePtr * const
D length 10U 0 const
*
D list_addAll PR N extproc('list_addAll')
D listPtr * const
D srcListPtr * const
*
D list_remove PR N extproc('list_remove')
D listPtr * const
D index 10U 0 const
*
D list_removeFirst...
D PR N extproc('list_removeFirst')
D listPtr * const
*
D list_removeLast...
D PR N extproc('list_removeLast')
D listPtr * const
*
D list_clear PR N extproc('list_clear')
D listPtr * const
*
D list_isEmpty PR N extproc('list_isEmpty')
D listPtr * const
*
D list_replace PR N extproc('list_replace')
D listPtr * const
D ptrValue * const
D lengthValue 10U 0 const
D index 10U 0 const
*
D list_get PR * extproc('list_get')
D listPtr * const
D index 10U 0 const
*
D list_getFirst PR * extproc('list_getFirst')
D listPtr * const
*
D list_getLast PR * extproc('list_getLast')
D listPtr * const
*
D list_getNext PR * extproc('list_getNext')
D listPtr * const
*
D list_iterate PR * extproc('list_iterate')
D listPtr * const
*
D list_getPrev PR * extproc('list_getPrev')
D listPtr * const
*
D list_abortIteration...
D PR extproc('list_abortIteration')
D listPtr * const
*
D list_resetIteration...
D PR extproc('list_resetIteration')
D listPtr * const
*
D list_contains PR N extproc('list_contains')
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D list_indexOf PR 10I 0 extproc('list_indexOf')
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D list_lastIndexOf...
D PR 10I 0 extproc('list_lastIndexOf')
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D list_toCharArray...
D PR extproc('list_toCharArray')
D listPtr * const
D arrayPtr * const
D count 10U 0 const
D length 10U 0 const
*
D list_size PR 10U 0 extproc('list_size')
D listPtr * const
*
D list_sublist PR * extproc('list_sublist')
D listPtr * const
D startIndex 10U 0 const
D length 10U 0 const options(*nopass)
*
D list_rotate PR extproc('list_rotate')
D listPtr * const
D rotatePos 10I 0 const
*
D list_swap PR N extproc('list_swap')
D listPtr * const
D itemPos1 10U 0 const
D itemPos2 10U 0 const
*
D list_foreach...
D PR extproc('list_foreach')
D listPtr * const
D procPtr * const procptr
D userData * const options(*nopass)
*
D list_toString PR 65535A varying extproc('list_toString')
D listPtr * const
D separator 1A const varying options(*omit:*nopass)
D enclosing 100A const varying options(*nopass)
D enclosingEnd 100A const varying options(*nopass)
*
D list_split PR * extproc('list_split') opdesc
D string 65535A const options(*varsize)
D separator 1A const options(*nopass)
*
D list_reverse PR extproc('list_reverse')
D listPtr * const
*
D list_copy PR * extproc('list_copy')
D listPtr * const
*
D list_frequency...
D PR 10U 0 extproc('list_frequency')
D listPtr * const
D valuePtr * const
D valueLength 10U 0 const
*
D list_addString...
D PR N extproc('list_addString') opdesc
D listPtr * const
D value 65535A const options(*varsize)
D index 10U 0 const options(*nopass)
*
D list_addInteger...
D PR N extproc('list_addInteger')
D listPtr * const
D value 10I 0 const
D index 10U 0 const options(*nopass)
*
D list_addLong...
D PR N extproc('list_addLong')
D listPtr * const
D value 20I 0 const
D index 10U 0 const options(*nopass)
*
D list_addShort...
D PR N extproc('list_addShort')
D listPtr * const
D value 5I 0 const
D index 10U 0 const options(*nopass)
*
D list_addFloat...
D PR N extproc('list_addFloat')
D listPtr * const
D value 4F const
D index 10U 0 const options(*nopass)
*
D list_addDouble...
D PR N extproc('list_addDouble')
D listPtr * const
D value 8F const
D index 10U 0 const options(*nopass)
*
D list_addBoolean...
D PR N extproc('list_addBoolean')
D listPtr * const
D value N const
D index 10U 0 const options(*nopass)
*
D list_addDecimal...
D PR N extproc('list_addDecimal')
D listPtr * const
D value 15P 5 const
D index 10U 0 const options(*nopass)
*
D list_addDate...
D PR N extproc('list_addDate')
D listPtr * const
D value D const
D index 10U 0 const options(*nopass)
*
D list_getString...
D PR 65535A extproc('list_getString')
D listPtr * const
D index 10U 0 const
*
D list_getInteger...
D PR 10I 0 extproc('list_getInteger')
D listPtr * const
D index 10U 0 const
*
D list_getShort...
D PR 5I 0 extproc('list_getShort')
D listPtr * const
D index 10U 0 const
*
D list_getLong...
D PR 20I 0 extproc('list_getLong')
D listPtr * const
D index 10U 0 const
*
D list_getFloat...
D PR 4F extproc('list_getFloat')
D listPtr * const
D index 10U 0 const
*
D list_getDouble...
D PR 8F extproc('list_getDouble')
D listPtr * const
D index 10U 0 const
*
D list_getBoolean...
D PR N extproc('list_getBoolean')
D listPtr * const
D index 10U 0 const
*
D list_getDecimal...
D PR 15P 5 extproc('list_getDecimal')
D listPtr * const
D index 10U 0 const
*
D list_getDate...
D PR D extproc('list_getDate')
D listPtr * const
D index 10U 0 const
*
D list_sort PR extproc('list_sort')
D listPtr * const
D sortAlgo * const procptr
*
D list_removeRange...
D PR extproc('list_removeRange')
D listPtr * const
D index 10U 0 const
D numberElements...
D 10U 0 const
*
D list_merge...
D PR extproc('list_merge')
D destList * const
D sourceList * const
D skipDuplicates...
D N const options(*nopass)
/endif
/copy 'llist_so_h.rpgle'
llist/llist_in_h.rpgle 100700 241 0 7234 11311761165 12667 0 ustar 00IUSR0001 *-------------------------------------------------------------------------
* Internally used Prototypes
*-------------------------------------------------------------------------
D memcpy PR extproc('memcpy')
D source * value
D dest * value
D length 10U 0 value
*
D memcmp PR 10I 0 extproc('memcmp')
D buffer1 * value
D buffer2 * value
D length 10U 0 value
*
D getToken PR * extproc('strtok')
D string * value options(*string)
D delim * value options(*string)
*
D getStringLength...
D PR 10U 0 extproc('strlen')
D string * value
*
D isLinkedListImpl...
D PR N
D listPtr * const
*
D sendEscapeMessage...
D PR
D id 10I 0 const
*
D getListEntryDs...
D PR *
D listPtr * const
D pos 10I 0 const
*
D internal_swap PR N
D listPtr * const
D itemPos1 10U 0 const options(*omit)
D itemPos2 10U 0 const options(*omit)
D itemPtr1 * const options(*nopass)
D itemPtr2 * const options(*nopass)
*-------------------------------------------------------------------------
* Variables
*-------------------------------------------------------------------------
/*
* If the list has only one entry, the pointer for the first and last
* entry points to the same entry. If the list has no entries both pointers
* has a *null value.
*
*
*
* The field iteration has the default value of -1. It means that no
* iteration is currently going on.
*
*/
D tmpl_header DS qualified based(nullPointer)
D id 20A
D size 10U 0
D bytes 10U 0
D firstEntry *
D lastEntry *
D iteration 10I 0
D iterNextEntry...
D *
D iterPrevEntry...
D *
D heapId 10I 0
*
D tmpl_entry DS qualified based(nullPointer)
D prev *
D next *
D value *
D length 10I 0
*
D hexNull S 1A inz(HEX_NULL)
*-------------------------------------------------------------------------
* Constants
*-------------------------------------------------------------------------
D HEX_NULL C x'00'
D LIST_ID C 'LIST_IMPLEMENTATION'
*
* Message IDs
*
D MSG_NO_LIST_IMPL...
D C 1
D MSG_POSITION_OUT_OF_BOUNDS...
D C 2
D MSG_INVALID_VALUE_TYPE...
D C 3
llist/llist_sort.rpgle 100700 241 0 12436 11535751364 12771 0 ustar 00IUSR0001 /**
* \brief Linked List : Sorting Algorithms
*
*
* \author Mihael Schmidt
* \date 2009-02-17
*
*/
*------------------------------------------------------------------------
*
* Copyright (c) 2007-2009 Mihael Schmidt
* All rights reserved.
*
* This file is part of the LLIST service program.
*
* LLIST is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* LLIST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with LLIST. If not, see http://www.gnu.org/licenses/.
*
*------------------------------------------------------------------------
H NOMAIN
H COPYRIGHT('Copyright (c) 2007-2009 Mihael Schmidt. All rights reserved.')
*---------------------------------------------------------------
* Prototypen
*---------------------------------------------------------------
/copy 'llist_h.rpgle'
/copy 'llist_in_h.rpgle'
/copy 'ceeapi_h.rpgle'
*-------------------------------------------------------------------------
* Procedures
*-------------------------------------------------------------------------
/**
* \brief Insertion sort
*
* The list will be sorted inline.
*
* \author Mihael Schmidt
* \date 2009-02-17
*
* \param Pointer to the list
*/
P list_sort_insertionSort...
P B export
D PI
D listPtr * const
*
D header DS likeds(tmpl_header) based(listPtr)
D keepRunning S N inz(*on)
D entryPtr1 S *
D entry1 DS likeds(tmpl_entry) based(entryPtr1)
D entryPtr2 S *
D entry2 DS likeds(tmpl_entry) based(entryPtr2)
D rc S 10I 0
D length S 10U 0
D shouldSwap S N inz(*off)
D top S N inz(*off)
D bottom S N inz(*off)
/free
if (header.size <= 1);
return;
endif;
entryPtr1 = getListEntryDs(listPtr : 0);
entryPtr2 = getListEntryDs(listPtr : 1);
dow (keepRunning);
if (entry1.length < entry2.length);
length = entry1.length;
else;
length = entry2.length;
endif;
rc = memcmp(entry1.value : entry2.value : length);
if (rc > 0);
shouldSwap = *on;
elseif (rc = 0 and entry1.length > entry2.length); // check the length of the values
shouldSwap = *on;
else;
// correct order => go down again
shouldSwap = *off;
endif;
if (shouldSwap);
top = *off;
bottom = *off;
internal_swap(listPtr : *omit : *omit : entryPtr1 : entryPtr2);
//
// get next entries to check
//
// check if we are already at the top
if (entry2.prev <> *null); // note: entry2 is now above entry1
// go one up
entryPtr1 = entry2.prev;
else;
// we are at the top, now go down again
top = *on;
// skip one entry because we just made the check
if (entry1.next <> *null);
entryPtr2 = entry1.next;
else;
bottom = *on;
endif;
endif;
else;
// check next entries
if (bottom); // need to go up
if (entry1.prev <> *null);
entryPtr2 = entryPtr1;
entryPtr1 = entry2.prev;
else;
top = *on;
// go down
entryPtr1 = entryPtr2;
entryPtr2 = entry1.next;
endif;
else; // need to go down
if (entry2.next <> *null);
entryPtr1 = entryPtr2;
entryPtr2 = entry1.next;
else;
bottom = *on;
if (entry1.prev <> *null);
// go up again
entryPtr2 = entryPtr1;
entryPtr1 = entry2.prev;
else;
top = *on;
endif;
endif;
endif;
endif;
// if both ends have been visited without change => end loop
if (top and bottom);
keepRunning = *off;
endif;
// reset things
shouldSwap = *off;
enddo;
/end-free
P E
llist/llist_so_h.rpgle 100700 241 0 651 11311761165 12656 0 ustar 00IUSR0001 /if not defined(LLIST_SORT)
/define LLIST_SORT
*------------------------------------------------------------------------
* Prototypes
*------------------------------------------------------------------------
D list_sort_insertionSort...
D PR extproc('list_sort_insertionSort')
D listPtr * const
/endif
llist/ceeapi_h.rpgle 100700 241 0 16157 11311761165 12324 0 ustar 00IUSR0001 /if not defined (CEEAPI)
/define CEEAPI
*-------------------------------------------------------------------------
* ILE CEE API Prototypes
*-------------------------------------------------------------------------
D cee_getOpDescInfo...
D PR extproc('CEEDOD')
D position 10I 0 const
D descType 10I 0
D dataType 10I 0
D descInfo1 10I 0
D descInfo2 10I 0
D length 10I 0
D feedback 12A options(*omit)
*-------------------------------------------------------------------------
* Date API Prototypes
*-------------------------------------------------------------------------
D cee_getLilianDate...
D PR extproc('CEEDAYS') opdesc
D charDate 20A const options(*varsize)
D formatString 20A const options(*varsize)
D lilianDate 10I 0
D errorcode 100A options(*varsize : *nopass)
*
D cee_getDateFromLilian...
D PR extproc('CEEDATE') opdesc
D lilianDate 10I 0 const
D formatString 20A const options(*varsize)
D dateString 20A options(*varsize)
D errorcode 100A options(*varsize : *nopass)
*
* CEEDYWK returns the weekday as a number between 1 and 7
*
* 1 = Sonntag / Sunday
* 2 = Montag / Monday
* 3 = Dienstag / Tuesday
* 4 = Mittwoch / Wednesday
* 5 = Donnerstag / Thursday
* 6 = Freitag / Friday
* 7 = Samstag / Saturday
*
* 0 = Fehler bei der Berechnung / ungültiges Datum
*
D cee_getDayOfWeekNumeric...
D PR extproc('CEEDYWK') opdesc
D lilianDate 10I 0 const
D dayOfWeek 10I 0
D errorcode 100A options(*varsize : *nopass)
*
*-------------------------------------------------------------------------
* Memory Management API Prototypes
*-------------------------------------------------------------------------
* Interface to the CEEGTST API (Get Heap Storage).
* 1) HeapId = Id of the heap.
* 2) Size = Number of bytes to allocate
* 3) RetAddr= Return address of the allocated storage
* 4) *OMIT = The feedback parameter. Specifying *OMIT here
* means that we will receive an exception from
* the API if it cannot satisfy our request.
* Since we do not monitor for it, the calling
* procedure will receive the exception.
*-------------------------------------------------------------------------
D cee_getStorage...
D PR extproc('CEEGTST')
D heapId 10I 0 const
D size 10I 0 const
D retAddr *
D feedback 12A options(*omit)
*-------------------------------------------------------------------------
* Interface to the CEEFRST API (Free Storage).
* 1) Addr = Address of the allocated storage to be freed
* 2) *OMIT = The feedback parameter. Specifying *OMIT here
* means that we will receive an exception from
* the API if it cannot satisfy our request.
* Since we do not monitor for it, the calling
* procedure will receive the exception.
*-------------------------------------------------------------------------
D cee_freeStorage...
D PR extproc('CEEFRST')
D address *
D feedback 12A options(*omit)
*-------------------------------------------------------------------------
* Interface to the CEECZST API (Reallocate Storage).
* 1) Addr = Address of the allocated storage
* 2) Size = New size (number of bytes) of the allocated storage
* 3) *OMIT = The feedback parameter. Specifying *OMIT here
* means that we will receive an exception from
* the API if it cannot satisfy our request.
* Since we do not monitor for it, the calling
* procedure will receive the exception.
*-------------------------------------------------------------------------
D cee_reallocateStorage...
D PR extproc('CEECZST')
D address *
D size 10I 0 const
D feedback 12A options(*omit)
*-------------------------------------------------------------------------
* Interface to the CEECRHP API (Create Heap).
* 1) HeapId = Id of the heap.
* 2) InitSize = Initial size of the heap.
* 3) Incr = Number of bytes to increment if heap must be
* enlarged.
* 4) AllocStrat = Allocation strategy for this heap. We will
* specify a value of 0 which allows the system
* to choose the optimal strategy.
* 5) *OMIT = The feedback parameter. Specifying *OMIT here
* means that we will receive an exception from
* the API if it cannot satisfy our request.
* Since we do not monitor for it, the calling
* procedure will receive the exception.
*-------------------------------------------------------------------------
D cee_createHeap...
D PR extproc('CEECRHP')
D heapId 10I 0
D initSize 10I 0 const options(*omit)
D increment 10I 0 const options(*omit)
D allocStrat 10I 0 const options(*omit)
D feedback 12A options(*omit)
*-------------------------------------------------------------------------
* Interface to the CEEDSHP API (Discard Heap).
* 1) HeapId = Id of the heap.
* 2) *OMIT = The feedback parameter. Specifying *OMIT here
* means that we will receive an exception from
* the API if it cannot satisfy our request.
* Since we do not monitor for it, the calling
* procedure will receive the exception.
*-------------------------------------------------------------------------
D cee_discardHeap...
D PR extproc('CEEDSHP')
D heapId 10I 0
D feedback 12A options(*omit)
/endif
llist/libc_h.rpgle 100700 241 0 10707 11311761165 12002 0 ustar 00IUSR0001 /if not defined LIBC
/define LIBC
*-------------------------------------------------------------------------
* Prototypes for C-Functions
*-------------------------------------------------------------------------
/if not defined(QUSEC)
/define QUSEC
/copy QSYSINC/QRPGLESRC,QUSEC
/endif
*
* string functions
*
D strtok PR * extproc('strtok')
D i_string * value options(*string)
D i_token * value options(*string)
*
D strlen PR 10U 0 extproc('strlen')
D string * value
*
D requestControlBlockLower...
D DS qualified
D type 10I 0 inz(0)
D ccsid 10I 0 inz(0)
D case 10I 0 inz(0)
D res1 10A inz(*ALLX'00')
*
D requestControlBlockUpper...
D DS qualified
D type 10I 0 inz(1)
D ccsid 10I 0 inz(0)
D case 10I 0 inz(0)
D res1 10A inz(*ALLX'00')
*
D caseConvert PR extproc('QlgConvertCase')
D reqContBlock const
D likeds(requestControlBlockUpper)
D input 1024A const options(*varsize)
D output 1024A options(*varsize)
D len 10I 0 const
D errorcode likeds(QUSEC) options(*varsize)
*
* memory functions
*
D memcpy PR * extproc('memcpy')
D dest * value
D source * value
D count 10U 0 value
*
D memset PR * extproc('memset')
D i_pDest * value
D i_char 10I 0 value
D i_count 10U 0 value
*
D memmove PR * extproc('memmove')
D pMemDest * value
D pMemSrc * value
D memSize 10U 0 value
*
D memcmp PR 10I 0 extproc('memcmp')
D pBuf1 * value
D pBuf2 * value
D count 10U 0 value
*
D memicmp PR 10I 0 extproc('__memicmp')
D pBuf1 * value
D pBuf2 * value
D count 10U 0 value
*
* math functions
*
D ceiling PR 8F extproc('ceil')
D value 8F value
*
D floor PR 8F extproc('floor')
D value 8F value
*
* other functions
*
D tmpnam PR * extproc('tmpnam')
D buffer 39A options(*omit)
*
D tmpnamIFS PR * extproc('_C_IFS_tmpnam')
D buffer 39A options(*omit)
*
D system PR 10I 0 extproc('system')
D command * value options(*string)
*
D srand PR extproc('srand')
D i_seed 10U 0 value
*
D rand PR 10I 0 extproc('rand')
*
D qsort PR * extproc('qsort')
D memPtr * value
D numElem 10U 0 value
D width 10U 0 value
D pSortFunc * value procptr
*
D bsearch PR * extproc('bsearch')
D keyPtr * value
D memPtr * value
D numElem 10U 0 value
D width 10U 0 value
D pSearchFnc * value procptr
/endif
llist/llist.bnd 100700 241 0 33237 11527654311 11351 0 ustar 00IUSR0001 /*
Copyright (c) 2007-2011 Mihael Schmidt
All rights reserved.
This file is part of the LLIST service program.
LLIST is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
LLIST is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with LLIST. If not, see http://www.gnu.org/licenses/.
*/
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('LLIST 1.3.0')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
EXPORT SYMBOL('list_getString')
EXPORT SYMBOL('list_getInteger')
EXPORT SYMBOL('list_getShort')
EXPORT SYMBOL('list_getLong')
EXPORT SYMBOL('list_getFloat')
EXPORT SYMBOL('list_getDouble')
EXPORT SYMBOL('list_getBoolean')
EXPORT SYMBOL('list_getDecimal')
EXPORT SYMBOL('list_getDate')
EXPORT SYMBOL('list_addString')
EXPORT SYMBOL('list_addInteger')
EXPORT SYMBOL('list_addShort')
EXPORT SYMBOL('list_addLong')
EXPORT SYMBOL('list_addFloat')
EXPORT SYMBOL('list_addDouble')
EXPORT SYMBOL('list_addBoolean')
EXPORT SYMBOL('list_addDecimal')
EXPORT SYMBOL('list_addDate')
EXPORT SYMBOL('list_sort')
EXPORT SYMBOL('list_sort_insertionSort')
EXPORT SYMBOL('list_removeRange')
EXPORT SYMBOL('list_merge')
EXPORT SYMBOL('list_resetIteration')
EXPORT SYMBOL('list_iterate')
ENDPGMEXP
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('LLIST 1.2.0')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
EXPORT SYMBOL('list_getString')
EXPORT SYMBOL('list_getInteger')
EXPORT SYMBOL('list_getShort')
EXPORT SYMBOL('list_getLong')
EXPORT SYMBOL('list_getFloat')
EXPORT SYMBOL('list_getDouble')
EXPORT SYMBOL('list_getBoolean')
EXPORT SYMBOL('list_getDecimal')
EXPORT SYMBOL('list_getDate')
EXPORT SYMBOL('list_addString')
EXPORT SYMBOL('list_addInteger')
EXPORT SYMBOL('list_addShort')
EXPORT SYMBOL('list_addLong')
EXPORT SYMBOL('list_addFloat')
EXPORT SYMBOL('list_addDouble')
EXPORT SYMBOL('list_addBoolean')
EXPORT SYMBOL('list_addDecimal')
EXPORT SYMBOL('list_addDate')
EXPORT SYMBOL('list_sort')
EXPORT SYMBOL('list_sort_insertionSort')
EXPORT SYMBOL('list_removeRange')
EXPORT SYMBOL('list_merge')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.1.0')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
EXPORT SYMBOL('list_getString')
EXPORT SYMBOL('list_getInteger')
EXPORT SYMBOL('list_getShort')
EXPORT SYMBOL('list_getLong')
EXPORT SYMBOL('list_getFloat')
EXPORT SYMBOL('list_getDouble')
EXPORT SYMBOL('list_getBoolean')
EXPORT SYMBOL('list_getDecimal')
EXPORT SYMBOL('list_getDate')
EXPORT SYMBOL('list_addString')
EXPORT SYMBOL('list_addInteger')
EXPORT SYMBOL('list_addShort')
EXPORT SYMBOL('list_addLong')
EXPORT SYMBOL('list_addFloat')
EXPORT SYMBOL('list_addDouble')
EXPORT SYMBOL('list_addBoolean')
EXPORT SYMBOL('list_addDecimal')
EXPORT SYMBOL('list_addDate')
EXPORT SYMBOL('list_sort')
EXPORT SYMBOL('list_sort_insertionSort')
EXPORT SYMBOL('list_removeRange')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.0.1')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
EXPORT SYMBOL('list_getString')
EXPORT SYMBOL('list_getInteger')
EXPORT SYMBOL('list_getShort')
EXPORT SYMBOL('list_getLong')
EXPORT SYMBOL('list_getFloat')
EXPORT SYMBOL('list_getDouble')
EXPORT SYMBOL('list_getBoolean')
EXPORT SYMBOL('list_getDecimal')
EXPORT SYMBOL('list_getDate')
EXPORT SYMBOL('list_addString')
EXPORT SYMBOL('list_addInteger')
EXPORT SYMBOL('list_addShort')
EXPORT SYMBOL('list_addLong')
EXPORT SYMBOL('list_addFloat')
EXPORT SYMBOL('list_addDouble')
EXPORT SYMBOL('list_addBoolean')
EXPORT SYMBOL('list_addDecimal')
EXPORT SYMBOL('list_addDate')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.0')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
EXPORT SYMBOL('list_getString')
EXPORT SYMBOL('list_getInteger')
EXPORT SYMBOL('list_getShort')
EXPORT SYMBOL('list_getLong')
EXPORT SYMBOL('list_getFloat')
EXPORT SYMBOL('list_getDouble')
EXPORT SYMBOL('list_getBoolean')
EXPORT SYMBOL('list_getDecimal')
EXPORT SYMBOL('list_getDate')
EXPORT SYMBOL('list_addString')
EXPORT SYMBOL('list_addInteger')
EXPORT SYMBOL('list_addShort')
EXPORT SYMBOL('list_addLong')
EXPORT SYMBOL('list_addFloat')
EXPORT SYMBOL('list_addDouble')
EXPORT SYMBOL('list_addBoolean')
EXPORT SYMBOL('list_addDecimal')
EXPORT SYMBOL('list_addDate')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.0RC6')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
EXPORT SYMBOL('list_copy')
EXPORT SYMBOL('list_frequency')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.0RC5')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV) SIGNATURE('LLIST 1.0RC4')
EXPORT SYMBOL('list_create')
EXPORT SYMBOL('list_dispose')
EXPORT SYMBOL('list_add')
EXPORT SYMBOL('list_addFirst')
EXPORT SYMBOL('list_addLast')
EXPORT SYMBOL('list_addAll')
EXPORT SYMBOL('list_remove')
EXPORT SYMBOL('list_removeFirst')
EXPORT SYMBOL('list_removeLast')
EXPORT SYMBOL('list_clear')
EXPORT SYMBOL('list_isEmpty')
EXPORT SYMBOL('list_replace')
EXPORT SYMBOL('list_get')
EXPORT SYMBOL('list_getFirst')
EXPORT SYMBOL('list_getLast')
EXPORT SYMBOL('list_getNext')
EXPORT SYMBOL('list_getPrev')
EXPORT SYMBOL('list_abortIteration')
EXPORT SYMBOL('list_contains')
EXPORT SYMBOL('list_indexOf')
EXPORT SYMBOL('list_lastIndexOf')
EXPORT SYMBOL('list_toCharArray')
EXPORT SYMBOL('list_size')
EXPORT SYMBOL('list_sublist')
EXPORT SYMBOL('list_rotate')
EXPORT SYMBOL('list_swap')
EXPORT SYMBOL('list_foreach')
EXPORT SYMBOL('list_toString')
EXPORT SYMBOL('list_split')
EXPORT SYMBOL('list_reverse')
ENDPGMEXP
llist/install.txt 100700 241 0 2536 11543166335 11724 0 ustar 00IUSR0001 Linked List Service Program Installation
These service program sources come as IFS files (not database file sources) and
with that has all the pros and cons of it.
The installation of this service program is really easy as it is accomplished
with the tool "make". The make tool is very much used in the Unix/Linux world.
To use it just type make in a QShell session (command qsh).
Requirements: You need a folder in the IFS for your global copy books (like /usr/local/include).
1. Download sources
2. FTP to IBM i server
3. It is a good idea to create a common source folder for IFS sources (mkdir /usr/local/src)
4. Extract sources (tar -xf llist.tar)
5. Check the CCSID of the Makefile script with ls -S message
(it should have 437, 819, 850 or something like that. 37 won't work.
You can convert the file(s) with the conversion script,
see http://www.rpgnextgen.com/index.php?content=resources)
6. edit the Makefile to match your environment (mostly the BIN_LIB and INCLUDE variable),
use edtf or RDP or RPG Next Gen Editor
7. make
8. make install (to copy the prototypes to the include folder)
9. make clean (removes the rpg module and the binder source file)
FINISHED!
Now you got your service program installed.
If you got any questions just drop me a mail ( mihael at rpgnextgen.com ).
Mihael
llist/lgpl-3.0.txt 100666 241 0 16743 11525304332 11541 0 ustar 00IUSR0001 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
llist/unittest 42777 241 0 0 11527663264 11234 5 ustar 00IUSR0001 llist/unittest/Makefile 100666 241 0 2434 11531263636 13043 0 ustar 00IUSR0001 #
# Makefile for Linked List Unit Tests
#
#
# NOTE: You nee the RUTESTCASE and LLIST service program in your current library
# to build the test cases.
#
#-----------------------------------------------------------
# User-defined part start
#
# BIN_LIB is the destination library for the service program.
# the rpg modules and the binder source file are also created in BIN_LIB.
# binder source file and rpg module can be remove with the clean step (make clean)
BIN_LIB=QGPL
# to this library the prototype source file (copy book) is copied in the install step
INCLUDE=/usr/local/include
# CFLAGS = RPG compile parameter
CFLAGS=DBGVIEW(*LIST) INCDIR('$(INCLUDE)')
# LFLAGS = binding parameter
# (make sure modules and service programs are in library list)
LFLAGS=BNDDIR(QC2LE) BNDSRVPGM(LLIST)
FROM_CCSID=37
#
# User-defined part end
#-----------------------------------------------------------
MODULES = llist_ut_1
OBJECTS = $(BIN_LIB)/llist_ut_1
.SUFFIXES: .rpgle .c .cpp
# suffix rules
.rpgle:
system "CRTRPGMOD $(BIN_LIB)/$@ SRCSTMF('$<') $(CFLAGS)"
system "crtsrvpgm $(BIN_LIB)/llist_ut_1 export(*all) bndsrvpgm(rutestcase llist)"
all: build
.PHONY:
llist_ut_1:
build: $(MODULES)
clean:
-system "DLTMOD $(BIN_LIB)/LLIST_UT_1"
-system "DLTSRVPGM $(BIN_LIB)/LLIST_UT_1"
llist/unittest/llist_ut_1.rpgle 100666 241 0 20611 11531263241 14522 0 ustar 00IUSR0001 /**
* \brief Linked List : Unit Test
*
* \author Mihael Schmidt
* \date 19.02.2011
*/
H nomain
*-------------------------------------------------------------------------
* Prototypes
*-------------------------------------------------------------------------
D getIntegerList PR *
D numberElements...
D 10I 0 const
*
D iterateList PR
D list * const
*
D test_create...
D PR
D test_sublist...
D PR
D test_size...
D PR
D test_merge...
D PR
D test_merge_no_skip...
D PR
D test_merge_skip...
D PR
D test_foreach...
D PR
*
D local_foreach PR extproc('local_foreach')
D entryValue * const
*
D local_foreach_with_userdata...
D PR extproc('local_foreach_with_-
D userdata')
D entryValue * const
D userdata * const
/copy RPGUNIT1,TESTCASE
/copy 'llist_h.rpgle'
*-------------------------------------------------------------------------
* Globals
*-------------------------------------------------------------------------
D foreachSum S 10I 0
P test_create...
P B export
*
D list S *
/free
list = list_create();
assert(list <> *null : 'Newly created list object mustn''t be null.');
list_dispose(list);
/end-free
P E
P test_size...
P B export
*
D list S *
/free
list = list_create();
iEqual(0 : list_size(list));
list_addInteger(list : 358);
iEqual(1 : list_size(list));
list_addInteger(list : 100);
iEqual(2 : list_size(list));
list_addInteger(list : 200);
iEqual(3 : list_size(list));
list_removeFirst(list);
iEqual(2 : list_size(list));
list_removeLast(list);
iEqual(1 : list_size(list));
list_clear(list);
iEqual(0 : list_size(list));
list_dispose(list);
/end-free
P E
P test_sublist...
P B export
*
D list S *
D sublist S *
/free
list = getIntegerList(5);
sublist = list_sublist(list : 2);
iEqual(3 : list_size(sublist));
iEqual(list_getInteger(list : 2) : list_getInteger(sublist : 0));
iEqual(list_getInteger(list : 3) : list_getInteger(sublist : 1));
iEqual(list_getInteger(list : 4) : list_getInteger(sublist : 2));
list_dispose(sublist);
sublist = list_sublist(list : 2 : 2);
iEqual(2 : list_size(sublist));
iEqual(list_getInteger(list : 2) : list_getInteger(sublist : 0));
iEqual(list_getInteger(list : 3) : list_getInteger(sublist : 1));
list_dispose(sublist);
sublist = list_sublist(list : 3 : 5);
iEqual(2 : list_size(sublist));
iEqual(list_getInteger(list : 3) : list_getInteger(sublist : 0));
iEqual(list_getInteger(list : 4) : list_getInteger(sublist : 1));
list_dispose(sublist);
list_dispose(list);
list_dispose(sublist);
/end-free
P E
P test_merge B export
*
D list S *
D list2 S *
/free
list = getIntegerList(3);
list2 = getIntegerList(5);
list_merge(list : list2);
iEqual(8 : list_size(list));
list_dispose(list);
list = list_create();
list_addInteger(list : 1);
list_addInteger(list : 2);
list_merge(list : list2);
iEqual(7 : list_size(list));
iEqual(1 : list_getInteger(list : 0));
iEqual(2 : list_getInteger(list : 1));
iEqual(15 : list_getInteger(list : 2));
iEqual(30 : list_getInteger(list : 3));
iEqual(45 : list_getInteger(list : 4));
iEqual(60 : list_getInteger(list : 5));
iEqual(75 : list_getInteger(list : 6));
list_dispose(list);
list_dispose(list2);
/end-free
P E
P test_merge_no_skip...
P B export
*
D list S *
D list2 S *
/free
list = getIntegerList(3);
list2 = getIntegerList(5);
list_merge(list : list2 : *off);
iEqual(8 : list_size(list));
list_dispose(list);
list = list_create();
list_addInteger(list : 1);
list_addInteger(list : 2);
list_merge(list : list2 : *off);
iEqual(7 : list_size(list));
iEqual(1 : list_getInteger(list : 0));
iEqual(2 : list_getInteger(list : 1));
iEqual(15 : list_getInteger(list : 2));
iEqual(30 : list_getInteger(list : 3));
iEqual(45 : list_getInteger(list : 4));
iEqual(60 : list_getInteger(list : 5));
iEqual(75 : list_getInteger(list : 6));
list_dispose(list);
list_dispose(list2);
/end-free
P E
P test_merge_skip...
P B export
*
D list S *
D list2 S *
/free
list = getIntegerList(3);
list2 = getIntegerList(5);
list_merge(list : list2 : *on);
iEqual(5 : list_size(list));
list_dispose(list);
list = list_create();
list_addInteger(list : 1);
list_addInteger(list : 2);
list_merge(list : list2 : *on);
iEqual(7 : list_size(list));
iEqual(1 : list_getInteger(list : 0));
iEqual(2 : list_getInteger(list : 1));
iEqual(15 : list_getInteger(list : 2));
iEqual(30 : list_getInteger(list : 3));
iEqual(45 : list_getInteger(list : 4));
iEqual(60 : list_getInteger(list : 5));
iEqual(75 : list_getInteger(list : 6));
list_dispose(list);
list_dispose(list2);
/end-free
P E
P test_foreach...
P B export
*
D list S *
/free
list = getIntegerList(3);
clear foreachSum;
list_foreach(list : %paddr('local_foreach'));
iEqual(90 : foreachSum);
clear foreachSum;
list_foreach(list : %paddr('local_foreach_with_userdata') :
%addr(foreachSum));
iEqual(90 : foreachSum);
list_dispose(list);
/end-free
P E
P getIntegerList B
D PI *
D numberElements...
D 10I 0 const
*
D list S *
D i S 10I 0
/free
list = list_create();
for i = 1 to numberElements;
list_addInteger(list : i * 15);
endfor;
return list;
/end-free
P E
P iterateList B
D PI
D list * const
*
D i S 10I 0 based(ptr)
/free
ptr = list_iterate(list);
dow (ptr <> *null);
dsply %char(i);
ptr = list_iterate(list);
enddo;
/end-free
P E
P local_foreach B
D PI
D entryValue * const
*
D value S 10I 0 based(entryValue)
/free
foreachSum += value;
/end-free
P E
P local_foreach_with_userdata...
P B
D PI
D entryValue * const
D userdata * const
*
D value S 10I 0 based(entryValue)
D sum S 10I 0 based(userdata)
/free
sum += value;
/end-free
P E
llist/Makefile 100666 241 0 3262 11542212330 11147 0 ustar 00IUSR0001 #
# Build script for Linked List
#
#-----------------------------------------------------------
# User-defined part start
#
# BIN_LIB is the destination library for the service program.
# the rpg modules and the binder source file are also created in BIN_LIB.
# binder source file and rpg module can be remove with the clean step (make clean)
BIN_LIB=QGPL
# to this library the prototype source file (copy book) is copied in the install step
INCLUDE=/usr/local/include
# CFLAGS = RPG compile parameter
RCFLAGS=OPTION(*SRCSTMT) DBGVIEW(*LIST) INCDIR('$(INCLUDE)') OPTIMIZE(*BASIC)
# CCFLAGS = C compiler parameter
CCFLAGS=OPTIMIZE(30) DBGVIEW(*LIST)
# LFLAGS = binding parameter
LFLAGS=BNDDIR(QC2LE) OPTION(*DUPPROC)
FROM_CCSID=37
#
# User-defined part end
#-----------------------------------------------------------
OBJECTS = llist llist_sort
.SUFFIXES: .rpgle .c .cpp
# suffix rules
.rpgle:
system "CRTRPGMOD $(BIN_LIB)/$@ SRCSTMF('$<') $(RCFLAGS)"
all: clean compile
llist:
llist_sort:
compile: llist.bnd $(OBJECTS)
system "CRTSRVPGM $(BIN_LIB)/LLIST MODULE($(BIN_LIB)/LLIST $(BIN_LIB)/LLIST_SORT) $(LFLAGS) EXPORT(*SRCFILE) SRCFILE($(BIN_LIB)/LLISTSRV) TEXT('Linked List')"
llist.bnd: .PHONY
-system "CRTSRCPF $(BIN_LIB)/LLISTSRV RCDLEN(112)"
-system "CPYFRMIMPF FROMSTMF('$@') TOFILE($(BIN_LIB)/LLISTSRV LLIST) RCDDLM(*ALL) STRDLM(*NONE) RPLNULLVAL(*FLDDFT)
install: llist.bnd
cp llist_h.rpgle $(INCLUDE)
cp llist_so_h.rpgle $(INCLUDE)
setccsid $(FROM_CCSID) $(INCLUDE)/llist_*
clean:
-system "DLTMOD $(BIN_LIB)/LLIST"
-system "DLTMOD $(BIN_LIB)/LLIST_SORT"
-system "DLTF $(BIN_LIB)/LLISTSRV"
dist-clean: clean
-system "DLTSRVPGM $(BIN_LIB)/LLIST"
.PHONY: