Author Topic: Ignoring certain blocks on output  (Read 17327 times)

0 Members and 1 Guest are viewing this topic.

S.Langhammer

  • Guest
Ignoring certain blocks on output
« on: March 25, 2013, 06:46:47 AM »
Hello again!
Those of you, who followed my questions here might know, that I'm working on a BricsCAD to custom file Lisp-Interface.
With the great help of you guys here on the swamp (specially Lee May and roy_043) I've worked my way through the Basic process of getting it up and running. Now it's optimization time!
Since I ignore certain entities on reading the File (such as viewports, 3Dsolids, Images and so on) it happens to me, that I give out empty blocks and inserts, that point to empty blocks.
These don't actually enlarge the interface's temp-file very much, but they slow down the visualization, since they are still being red in and calculated on the Delphi side of the Interface.

Now I thought there must be a way, to properly make a list of all "empty" blocks and only print those blocks and inserts to the file, who are not in that list.

I tried something with the length of the list of subentities within the block but my check function always got caught up on an endless loop.
I'll just post all my block and insert related code and if anyone gets an idea I'd be happy to hear it!


Code - Auto/Visual Lisp: [Select]
  1. (defun getBlockList(/ listBlock entName T)
  2.         (while (setq listBlock (tblnext "BLOCK" T))
  3.                 (while (setq entName (cdr(assoc -2 listBlock)))
  4.                         (getBlkRefData listBlock)
  5.                         (setq listBlock (entnext entName))
  6.                 )
  7.         )
  8.         (princ)
  9. )
  10. (defun Block_EnameListNested (blockName / ename ret blockName)
  11.         (if (setq ename (tblobjname "BLOCK" blockName))
  12.                 (while (setq ename (entnext ename))
  13.                         (setq ret (append ret (list ename)))
  14.                 )
  15.         )
  16.         ret
  17. )
  18.  
  19. (defun getBlkData(/ entName entPoint entX entY entZ entLay entRot dStr entScaX entScaY entScaZ endMark entNorm entNormStr)     
  20.         (setq entLay    (cdr(assoc 8 entity))
  21.                 entName (cdr(assoc 2 entity))
  22.                 entPoint        (cdr(assoc 10 entity))
  23.                 entX            (rtos (car   entPoint) 2 4)
  24.                 entY            (rtos (cadr  entPoint) 2 4)
  25.                 entZ    (rtos (caddr entPoint) 2 4)
  26.                 entScaX (rtos (cdr(assoc 41 entity)) 2 4)
  27.                 entScaY (rtos (cdr(assoc 42 entity)) 2 4)
  28.                 entScaZ (rtos (cdr(assoc 43 entity)) 2 4)
  29.                 entNorm (cdr(assoc 210 entity))
  30.                 entNormStr(strcat (rtos(car entNorm)2 4)spcr(rtos(cadr entNorm)2 4)spcr(rtos(caddr entNorm)2 4))
  31.         )
  32.         (if (setq entRot (cdr(assoc 50 entity)))
  33.                 (setq entRot (angtos (degtorad entRot) 0 4))
  34.                 (setq entRot "0.0000")
  35.         )
  36.         (if (= (substr entName 1 1) "*")  ; if theres an anonymus/autogenerated insert found (such as copies or from SAT entities the script converted) all its block information including subentities are written to the file
  37.                 (progn
  38.                         (setq dStr (strcat              "BLOCK" spcr)
  39.                                   dStr (strcat dStr entName spcr)
  40.                                   dStr (strcat dStr "\n")
  41.                                   endMark (strcat "End of " entName "\n")
  42.                         )
  43.                         (fileWriteString dStr)
  44.                         (getinfo (Block_EnameListNested entName))
  45.                         (fileWriteString endMark)
  46.                 )
  47.         )
  48.         (setq dStr (strcat      "INSERT"               spcr)
  49.                   dStr (strcat dStr entLay       spcr)
  50.                   dStr (strcat dStr entName    spcr)
  51.                   dStr (strcat dStr entX spcr entY spcr entZ spcr)
  52.                   dStr (strcat dStr entScaX      spcr)
  53.                   dStr (strcat dStr entScaY      spcr)
  54.                   dStr (strcat dStr entScaZ      spcr)
  55.                   dStr (strcat dStr entRot        spcr)
  56.                   dStr (strcat dStr entNormStr "\n")
  57.         )
  58.         (fileWriteString dStr)
  59.         (princ)
  60. )       ;;; ende getBlkData
  61.  
  62. (defun getBlkRefData(inBlock / entLyr dstr entPt entPtStr entName endMark)
  63.         (setq entName(cdr(assoc 2 inBlock)))
  64.         (if (/= (substr entName 1 1) "*")      ; ignoring anonymus/automatic generated blocks to prevent accedently reading blocks creatated by entities (as I red, dimensions generate blocks beginning with a * for example)
  65.                 (progn
  66.                         (setq dStr (strcat              "BLOCK" spcr)
  67.                                   dStr (strcat dStr entName "\n")
  68.                                   endMark (strcat "End of " entName "\n")
  69.                         )
  70.                         (fileWriteString dStr)
  71.                         (getinfo (Block_EnameListNested entName))
  72.                         (fileWriteString endMark)
  73.                 )
  74.         )
  75.         (princ)
  76. )
  77.  

Please excuse if there are some right parenthesis missing. I copied the code directly from the file and removed the German comments. I might have caught some parenthesis as well.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Ignoring certain blocks on output
« Reply #1 on: March 25, 2013, 08:10:07 AM »
Your problem is perhaps* caused by the first function (getBlockList).
There are two issues with the function.
First this is how (I think) it should look:
Code - Auto/Visual Lisp: [Select]
  1. (defun getBlockList(/ listBlock entName)
  2.   (while (setq listBlock (tblnext "BLOCK" (not listBlock))) ; (not listBlock) only returns T once.
  3.     (getBlkRefData listBlock)
  4.   )
  5.   (princ)
  6. )

Issue 1:
(getBlockList) will probably only work once. You are declaring T as a local variable. This means** that inside the function T has a value of nil. This means that your function is using this code (tblnext "BLOCK" nil) every time. When it should be using (tblnext "BLOCK" T) to 'rewind' the symbol table for the first entry and then (tblnext "BLOCK" nil) for the next entries.
See:
http://docs.autodesk.com/ACD/2011/ENU/filesALR/WS1a9193826455f5ff1a32d8d10ebc6b7ccc-6917.htm

Issue 2:
When you use this code: (setq listBlock (entnext entName)), listBlock is no longer a list and (cdr(assoc -2 listBlock)) will return nil.

* The endless loop may be due to the occurence to (tblsearch) somewhere else in your code.

** I think this is a bug in BricsCAD since T should have an immutable binding.

S.Langhammer

  • Guest
Re: Ignoring certain blocks on output
« Reply #2 on: March 25, 2013, 08:40:34 AM »
Looks like i expressed myself the wrong way. The functions you see there work perfectly fine, what I was searching for was more of an add-on to the existing code.
You are entirely right about the first issue. It actually does work only once. Yet that is just about right. The outer algorithm works about like this:
-choose a file
-create the temporary file
-start BricsCAD as Background procedure
-let it load the chosen file
-run the Lisp script
-close the file
-read the info from he file

About the second issue:
This is weird since it actually worked just fine so far. I never noticed an error around it. I'll definitely try your code, thank you.

... this actually surprises me since i find a lot of blocks in my temporary file. roy you made my day i got something to think of now!

S.Langhammer

  • Guest
Re: Ignoring certain blocks on output
« Reply #3 on: March 26, 2013, 10:04:00 AM »
I just recognized, that I can only identify a block, that holds no non-ignored entity, if I only collect the entity names of non-ignored entities with Block_EnameListNested, when I load each complete entity, filter its entity type and check if I should ignore it or not. Doing that for every single entity would take ages especially in huge files.
Thanks for the help anyway. Looks like we have to build some kind of ignore function into the Delphi code.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Ignoring certain blocks on output
« Reply #4 on: March 26, 2013, 12:50:19 PM »
... In theory you can change your (getinfo) function so that instead of writing directly to file it returns a string or nil (= all entities have been ignored). Your (getBlkData) would then have to be rewritten to contain something like this:
Code - Auto/Visual Lisp: [Select]
  1. (setq entName (cdr (assoc 2 entity)))
  2. (if (set tmpInfo (getinfo (Block_EnameListNested entName)))
  3.   (progn
  4.     (fileWriteString
  5.       (strcat
  6.         "BLOCK" spcr
  7.         entName spcr
  8.         "\n"
  9.       )
  10.     )
  11.     (fileWriteString tmpInfo)
  12.     (fileWriteString (strcat "End of " entName "\n")) ; endMark
  13.     ; ... code from line 20 etc.
  14.     ; ... code from line 48 etc.
  15.     ; ...
  16.   )
  17. )


S.Langhammer

  • Guest
Re: Ignoring certain blocks on output
« Reply #5 on: March 27, 2013, 03:46:46 AM »
The problem about making one LARGE info-string is, well its size.
I've tried this Kind of solution, when I first wrote getInfo. Basically lining up all red out entities to one sting. The problem here was the limitation given by the hardware. The process ate... devoured a large amount of ram and CPU capacity, causing it to slow down drastically. I'll try your solution but I have a bad feeling bout it. I should also mention, it's not the getInfo function itself, who writes to the file, it's every single get[entity type] who does that.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Ignoring certain blocks on output
« Reply #6 on: March 27, 2013, 06:42:55 AM »
I can imagine that:
Code - Auto/Visual Lisp: [Select]
  1. (setq outputString (strcat outputString "Something new"))
slows your program down when the outputString becomes extremely long.

When I write string data to a file I typically work with a list of strings.
This approach may also work for you:
Code - Auto/Visual Lisp: [Select]
  1. (setq outputStringList (cons  "Something new" outputStringList)) ; Note: using cons is much faster than append!
  2. ; ...
  3. ; ...
  4. (foreach line (reverse outputStringList) ; Reverse is required because of the use of cons.
  5.   (write-line line file)
  6. )

TheMaster

  • Guest
Re: Ignoring certain blocks on output
« Reply #7 on: March 28, 2013, 11:06:28 PM »
The problem about making one LARGE info-string is, well its size.
I've tried this Kind of solution, when I first wrote getInfo. Basically lining up all red out entities to one sting. The problem here was the limitation given by the hardware. The process ate... devoured a large amount of ram and CPU capacity, causing it to slow down drastically. I'll try your solution but I have a bad feeling bout it. I should also mention, it's not the getInfo function itself, who writes to the file, it's every single get[entity type] who does that.

Regarding this:

Quote
Code: [Select]
(setq dStr (strcat "INSERT"               spcr)
  dStr (strcat dStr entLay       spcr)
  dStr (strcat dStr entName    spcr)
  dStr (strcat dStr entX spcr entY spcr entZ spcr)
  dStr (strcat dStr entScaX      spcr)
  dStr (strcat dStr entScaY      spcr)
  dStr (strcat dStr entScaZ      spcr)
  dStr (strcat dStr entRot        spcr)
  dStr (strcat dStr entNormStr "\n")
)

Each call to (strcat) requires each string argument to
be copied to the result, which means that each result
is then passed back to (strcat) and must be copied
again, each and every time it is passed to (strcat).

If optimization is what you're after, then replace all of
the calls to (strcat) with a single call that takes as many
arguments as you need to produce the result.

See the attached file for some general tips on optimizing
string-related operations.


« Last Edit: March 29, 2013, 12:29:51 AM by TT »

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Ignoring certain blocks on output
« Reply #8 on: March 29, 2013, 07:53:38 AM »
Very informative, Thanks Tony
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1451
  • Marco
Re: Ignoring certain blocks on output
« Reply #9 on: March 29, 2013, 10:38:11 AM »
...
See the attached file for some general tips on optimizing
string-related operations.
Very interesting, thanks.
But I found a little problem in using read in:
Code: [Select]
(defun string->list (s delim)
   (read
      (vl-list->string
         (append
           '(40 34)        ;; add '("' to start
            (apply 'append
               (subst
                 '(34 34)
                  (vl-string->list delim)
                  (mapcar 'list (vl-string->list s))
               )
            )
           '(34 41)       ;; add '")" to end
         )
      )
   )
)
(string->list "\"Abc\",\"123\"" ",")           => ("" ABC "" "" 123 "")
(ALE_String2List "\"Abc\",\"123\"" ",")   => ("\"Abc\"" "\"123\"")    ; see below

About speed, also I have modified your code to:
(setq string->list-slow ALE_String2List)
Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:
  (string->list-slow): 0.034
  (string->list-fast): 0.5613

Code: [Select]
; Version 1.00 - November 2001
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;
(defun ALE_String2List (InpStr CarDlm / SttPos EndPos TmpLst)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)

TheMaster

  • Guest
Re: Ignoring certain blocks on output
« Reply #10 on: March 29, 2013, 07:17:29 PM »
Hi Marco.

Thanks for pointing that out.  I should've mentioned that the string->list kludge that uses (read) doesn't always work, and in fact, there are a few ways to break it.  I added that to the original content a long time ago, and never really tested it thoroughly.

I suppose if one is really stuck for lack of a better solution (e.g., non-LISP based), then this hacked-up version might address that specific problem, but not others:

Code: [Select]

(defun string->list (s delim)
   (read
      (vl-list->string
         (append
           '(40 34)        ;; add '("' to start
            (apply 'append
               (subst
                 '(34 34)
                  (vl-string->list delim)
                  (subst
                    '(92 34)
                    '(34)
                     (mapcar 'list (vl-string->list s))
                  )
               )
            )
           '(34 41)       ;; add '")" to end
         )
      )
   )
)


Command: (string->list "\"Abc\",\"123\"" ",")
("\"Abc\"" "\"123\"")


Again, this was only minimally-tested with your example, and I don't know if it works in every case

TheMaster

  • Guest
Re: Ignoring certain blocks on output
« Reply #11 on: March 29, 2013, 11:19:55 PM »

About speed, also I have modified your code to:
(setq string->list-slow ALE_String2List)
Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:
  (string->list-slow): 0.034
  (string->list-fast): 0.5613

Yes, that's very much better for cases where a single character
is used as the delimiter.

The code I posted was based on a simplified version of code
that splits a string at any one of several different delimiting
characters, and also removes empty strings between two or
more adjacent delimiters:

Code: [Select]

    (string-split "\t\tabc,123\n      xyz,456" "\n,\t ")
    => ("abc" "123" "xyz" "456")


It will also do hierarchical splits, as in:

Code: [Select]

  (string-split "x=10,y=25,z=0" '("," "="))
  => (("x" "10") ("y" "25") ("z" "0"))


« Last Edit: March 29, 2013, 11:46:12 PM by TT »

TheMaster

  • Guest
Re: Ignoring certain blocks on output
« Reply #12 on: March 30, 2013, 04:53:18 AM »
Code: [Select]
; Version 1.00 - November 2001
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;
(defun ALE_String2List (InpStr CarDlm / SttPos EndPos TmpLst)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)

Marco - After seeing your incredibly-fast solution, I went into my old LISP libraries to see why the one using the (read) kludge that I showed was relatively-slow.

Here is why my orange (the function which string->list was
based on) is slower than your apple  :laugh:

Code: [Select]

Command: (setq str "552.32,\"Smith, John\",42,350")
"552.32,\"Smith, John\",42,350"

Command: (ale_string2list str ",")
("552.32" "\"Smith" " John\"" "42" "350")

Command: (string-parse str ",")
("552.32" "\"Smith, John\"" "42" "350")


(string-parse) is the function which the string->list example function from that
document was based on. It was designed from the outset to parse CDF-formatted
data, where commas that appear between two double-quotes are interpreted as
literal text content, rather than as delimiters
. The string->list function was really
just for the purpose of comparing the two approaches, one using many calls to
(strcat) and the other using (read), and also suffers from the same problem shown
above.

Here is a watered-down version of string-parse (the actual working
version does additional things related to whitespace handling which
I've omitted because it is somewhat specific to the application I was
using it with):

Code: [Select]

(defun string-parse ( s delimiters / dquote ddquote flag )
   (cond
      (  (not delimiters) s)
      (  (vl-consp delimiters)
         (mapcar
            (function
               (lambda (str)
                  (string-parse str (cdr delimiters))
               )
            )
            (string-parse s (car delimiters))
         )
      )
      (t (setq dquote '(92 34))
         (setq ddquote '(34 34))
         (read
            (vl-list->string
               (append
                 '(40 34)       
                  (apply 'append
                     (mapcar
                        (function
                           (lambda (c)
                              (cond
                                 ;; escape double-quote and toggle flag

                                 (  (eq c 34) 
                                    (setq flag (not flag))
                                    dquote
                                 )

                                 ;; if flag is set, ignore delimiters:

                                 (flag (list c))

                                 ;; replace delimiter with 2 double-quotes

                                 (  (vl-string-position c delimiters) ddquote)

                                 (t (list c))
                              )
                           )
                        )
                        (vl-string->list s)
                     )
                  )
                 '(34 41)       
               )
            )
         )
      )
   )
)


« Last Edit: March 30, 2013, 05:29:00 AM by TT »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1451
  • Marco
Re: Ignoring certain blocks on output
« Reply #13 on: March 30, 2013, 05:14:45 AM »
<clip>
Again, this was only minimally-tested with your example, and I don't know if it works in every case
Thank Tony for your complete and accurate answer.
I have tested other conditions and it seems work good:
(string->list "\"Abc\",\"Abc\"" ",")                 => ("\"Abc\"" "\"Abc\"")
(string->list ".99,.99" ",")                             => (".99" ".99")
(string->list "1.0,1.0" ",")                                => ("1.0" "1.0")
(string->list "1,1" ",")                                   => ("1" "1")
(string->list "Xyz,Xyz" ",")                             => ("Xyz" "Xyz")
(string->list ",," ",")                                        => ("" "" "")
(string->list "(1 2 \"Abc\"),(1 2 \"Abc\")" ",") => ("(1 2 \"Abc\")" "(1 2 \"Abc\")")
(string->list "(1 . 2),(1 . 2)" ",")                => ("(1 . 2)" "(1 . 2)")
(string->list "(1/2\"Abc),(1/2\"Abc)" ",")       => ("(1/2\"Abc)" "(1/2\"Abc)")
(string->list ".,." ",")                                        => ("." ".")
(string->list "(,(" ",")                                     => ("(" "(")
(string->list "),),(,)" ",")                                 => (")" ")" "(" ")")

Ciao.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1451
  • Marco
Re: Ignoring certain blocks on output
« Reply #14 on: March 30, 2013, 07:14:54 AM »
<clip>
Tony,

this topic is always very interesting and full of new needs,
thank you for your teaching!

I answer to two your interventions using the old style:

>>>   (string-split "x=10,y=25,z=0" '("," "="))
>>>    => (("x" "10") ("y" "25") ("z" "0"))

very interesting!

>>>   (string-parse) is the function which the string->list
>>>   example function from that document was based on.
>>>   It was designed from the outset to parse CDF-formatted
>>>   data, where commas that appear between two double-quotes
>>>   are interpreted as literal text content, rather than
>>>   as delimiters.

Very correct, now I will try to write a new version for this  ;-)

Below two other functions for delimiter > 1 or more characters
and to remove dupes delimiter.

Grazie mille.

Code: [Select]
; John Uhden, Cadlantic/formerly CADvantage
; String2List
; Originally ALE_STRING2LIST By Marc'Antonio Alessi
; Date: Thursday, November 08, 2001
;
; Renamed in:
; Function: ALE_String2ListStrDlm
;
; Version 1.00
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter > 1 or more characters [STR]
;
; Examples:
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][(][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "(" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][)][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" ")" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][\"][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "\"" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][,][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "," "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][.][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "." "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][.99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" ".99")
;
; Return Values:
;   [LIST]
;
(defun ALE_String2ListStrDlm (InpStr StrDlm / SttPos TmpPos DlmLng TmpLst)
  (cond
    ( (/= (type InpStr) (type StrDlm) 'STR) )
    ( (= InpStr StrDlm) '("") )
    (T
      (setq
        DlmLng (strlen StrDlm)   SttPos 0
        TmpPos (vl-string-search StrDlm InpStr SttPos)
      )
      (while TmpPos
        (setq
          TmpLst (cons (substr InpStr (1+ SttPos) (- TmpPos SttPos)) TmpLst)
          SttPos (+ TmpPos DlmLng)
          TmpPos (vl-string-search StrDlm InpStr SttPos)
        )
      )
      (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
    )
  )
)

; Marc'Antonio Alessi, Italy - http://xoomer.virgilio.it/alessi
;
; Function: ALE_String_ToList
;
; Version 1.00 - 01/2010
;
; Description:
;   convert a string into a list of strings
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;   TrueFl = if nil remove dupes delimiter
;
; Examples:
;  (ALE_String_ToList "aaa_vvv_hhh__yyy ___lll_" "_" T)
;  ("aaa" "vvv" "hhh" "" "yyy " "" "" "lll" "lll")
;
;  (ALE_String_ToList "aaa_vvv_hhh__yyy ___lll_" "_" nil)
;  ("aaa" "vvv" "hhh" "yyy " "lll")
;
(defun ALE_String_ToList (InpStr CarDlm TrueFl / SttPos EndPos TmpLst TmpStr)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpStr (substr InpStr (1+ SttPos) (- EndPos SttPos))
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
    (and
      (or (/= TmpStr "") TrueFl)
      (setq TmpLst (cons TmpStr TmpLst))
    )
  )
  (if (or (/= (setq TmpStr (substr InpStr (1+ SttPos))) "") TrueFl)
    (reverse (cons TmpStr TmpLst))
    (reverse TmpLst)
  )
)