-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutil_mb.lisp
More file actions
2989 lines (2734 loc) · 106 KB
/
util_mb.lisp
File metadata and controls
2989 lines (2734 loc) · 106 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;mike.bobak@gmail a collection of utils
;threec utilities
(defun km-seqp+ (s) ;mv2 kmb/u2.lisp
(km-seqp (list+ s)))
;====start of sys.lisp
#|
Copyright (c) 2000-2006, Sunil Mishra All rights reserved. for99lines
|# ;;; $Id: system-standalone.lisp 97 2006-08-31 06:00:10Z smishra $
(defvar *source-file-extensions*
(list "lisp" "cl" "lsp"))
(defvar *compiled-file-extension*
#.(pathname-type (compile-file-pathname "foo")))
(defun file-newer-p (file1 file2)
(> (or (file-write-date file1) 0) (file-write-date file2)))
(defun find-file-with-type (pathname types
&optional (if-does-not-exist :error))
(or (cond ((pathname-type pathname)
;; Must be the full file path
(when (probe-file pathname)
pathname))
((stringp types)
(let ((pathname (make-pathname :type types :defaults pathname)))
(when (probe-file pathname)
pathname)))
(t (dolist (source-type types)
(let ((pathname
(make-pathname :type source-type :defaults pathname)))
(when (probe-file pathname)
(return pathname))))))
(ecase if-does-not-exist
((nil :soft) nil)
(:error (error "Source file corresponding to ~S does not exist."
pathname)))))
#-allegro
(defun compile-file-if-needed (source fasl verbose verbose-supplied-p
print print-supplied-p external-format force)
#+clisp (declare (ignore external-format))
(when (or force
(not (probe-file fasl))
(and source (file-newer-p source fasl)))
(loop
(multiple-value-bind (output-truename warnings-p failure-p)
(compile-file source :output-file fasl
:verbose (if verbose-supplied-p
verbose
*compile-verbose*)
:print (if print-supplied-p
print
*compile-print*)
#-clisp :external-format #-clisp external-format)
(if (or failure-p (and warnings-p (eql *break-on-signals* t)))
;; Todo: Also need a skip compilation restart.
(cerror "Retry compile." "Problems compiling ~S." source)
(return output-truename))))))
(defun compile-load (file &key (verbose nil verbose-supplied-p)
(print nil print-supplied-p) (if-does-not-exist :error)
(external-format :default) output-file force)
"Compile a file if source newer, and load."
(let* ((source (find-file-with-type (pathname file) *source-file-extensions*
nil))
(fasl (apply #'compile-file-pathname (or source file)
(when output-file
`(:output-file ,output-file)))))
(cond ((or source (probe-file fasl))
(let ((compile-result
#+allegro
(apply #'compile-file-if-needed source
`(,@(when verbose-supplied-p `(:verbose ,verbose))
,@(when print-supplied-p `(:print ,print))
,@(when output-file `(:output-file ,output-file))
:external-format ,external-format
:force-recompile ,force))
#-allegro
(compile-file-if-needed
source fasl verbose verbose-supplied-p print
print-supplied-p external-format force)))
(values
(load fasl :print (if print-supplied-p print *load-print*)
:verbose (if verbose-supplied-p verbose *load-verbose*)
:if-does-not-exist if-does-not-exist)
compile-result)))
(t
(case if-does-not-exist
(:error (error "Could not locate source or fasl for ~S." file))
((nil :soft) nil))))))
;rest in: ai/sw/sf/public/mcpat/trunk/system-standalone.lisp
;
;new
(defun lsp-p (f)
(member (pathname-type f) *source-file-extensions* :test #'equal))
(defun ls-lsp (&optional (d nil))
(collect-if #'lsp-p (ls d)))
;(defun asd-p (f) (suffixp ".asd" f))
(defun asd-p (f) (equal "asd" (pathname-type f)))
(defun ls-asd (&optional (d nil))
(collect-if #'asd-p (ls d)))
(defun asd1 (&optional (d nil))
"1st/smallest asd file in dir"
(first-lv (sort (ls-asd d) #'len<)))
;need2 str-cat the d in
(defun a1 (&optional (d nil))
"get root/sym of smallest asd file in dir"
(let ((as (asd1 d)))
(when as (intern (car-lv (split-strs2at as "."))))))
(defun la1 ()
"load most likely .asd file in this dir"
;(al (a1))
(let ((a1 (a1)))
(format t "~%(al '~a)" a1)
(al a1)))
;-alias s11 "sbcl --eval '(ql1)'"
(defun ql1 ()
"load most likely .asd file in this dir"
(let ((a1 (a1)))
(format t "~%(ql '~a)" a1)
(ql a1)))
;-
;(load-bps) ;mine is much nicer
(defun c-load (f) (compile-load f))
;(trace c-load)
(defun load-lsp (&optional (dir "tools/bps/"))
(let ((lf (ls-lsp dir)))
(when (full lf)
(mapcar #'c-load (mapcar #'(lambda (f) (strcat dir (pathname-name f))) lf)))))
;(setq *reasoner-loaded* t)
;====end of sys.lisp
;(in-package "LISA")
;util_mb.cl (in v3) =util-mb.cl + path.cl (from v2); Written/Collected by bobak@computer.org
;use: adjoin/pushnew, SET-EXCLUSIVE-OR, SUBSETP, getf/plist
(defun subl> (a b) (subsetp b a))
;==> /Users/bobak/Documents/downloads/lang/lsp/ai/ut/mfkb/km/run/two/ut/path.cl <==
;;; *****************************************************************************
(defun list-directory (dirname)
"Return a list of the contents of the directory named by dirname.
Names of subdirectories will be returned in `directory normal
form'. Unlike CL:DIRECTORY, LIST-DIRECTORY does not accept
wildcard pathnames; `dirname' should simply be a pathname that
names a directory. It can be in either file or directory form."
(when (wild-pathname-p dirname)
(error "Can only list concrete directory names."))
(let ((wildcard (directory-wildcard dirname)))
#+(or sbcl cmu lispworks)
;; SBCL, CMUCL, and Lispworks return subdirectories in directory
;; form just the way we want.
(directory wildcard)
#+openmcl
;; OpenMCl by default doesn't return subdirectories at all. But
;; when prodded to do so with the special argument :directories,
;; it returns them in directory form.
(directory wildcard :directories t)
#+allegro
;; Allegro normally return directories in file form but we can
;; change that with the :directories-are-files argument.
(directory wildcard :directories-are-files nil)
#+clisp
;; CLISP has a particularly idiosyncratic view of things. But we
;; can bludgeon even it into doing what we want.
(nconc
;; CLISP won't list files without an extension when :type is
;; wild so we make a special wildcard for it.
(directory wildcard)
;; And CLISP doesn't consider subdirectories to match unless
;; there is a :wild in the directory component.
(directory (clisp-subdirectories-wildcard wildcard)))
#-(or sbcl cmu lispworks openmcl allegro clisp)
(error "list-directory not implemented")))
(defun file-exists-p (pathname)
"Similar to CL:PROBE-FILE except it always returns directory names
in `directory normal form'. Returns truename which will be in
`directory form' if file named is, in fact, a directory."
#+(or sbcl lispworks openmcl)
;; These implementations do "The Right Thing" as far as we are
;; concerned. They return a truename of the file or directory if it
;; exists and the truename of a directory is in directory normal
;; form.
(probe-file pathname)
#+(or allegro cmu)
;; These implementations accept the name of a directory in either
;; form and return the name in the form given. However the name of a
;; file must be given in file form. So we try first with a directory
;; name which will return NIL if either the file doesn't exist at
;; all or exists and is not a directory. Then we try with a file
;; form name.
(or (probe-file (pathname-as-directory pathname))
(probe-file pathname))
#+clisp
;; Once again CLISP takes a particularly unforgiving approach,
;; signalling ERRORs at the slightest provocation.
;; pathname in file form and actually a file -- (probe-file file) ==> truename
;; pathname in file form and doesn't exist -- (probe-file file) ==> NIL
;; pathname in dir form and actually a directory -- (probe-directory file) ==> truename
;; pathname in dir form and doesn't exist -- (probe-directory file) ==> NIL
;; pathname in file form and actually a directory -- (probe-file file) ==> ERROR
;; pathname in dir form and actually a file -- (probe-directory file) ==> ERROR
(or (ignore-errors
;; PROBE-FILE will return the truename if file exists and is a
;; file or NIL if it doesn't exist at all. If it exists but is
;; a directory PROBE-FILE will signal an error which we
;; ignore.
(probe-file (pathname-as-file pathname)))
(ignore-errors
;; PROBE-DIRECTORY returns T if the file exists and is a
;; directory or NIL if it doesn't exist at all. If it exists
;; but is a file, PROBE-DIRECTORY will signal an error.
(let ((directory-form (pathname-as-directory pathname)))
(when (ext:probe-directory directory-form)
directory-form))))
#-(or sbcl cmu lispworks openmcl allegro clisp)
(error "list-directory not implemented"))
(defun no-such-file (fn)
"maybe more readable"
(not (file-exists-p fn)))
(defun directory-wildcard (dirname)
(make-pathname
:name :wild
:type #-clisp :wild #+clisp nil
:defaults (pathname-as-directory dirname)))
#+clisp
(defun clisp-subdirectories-wildcard (wildcard)
(make-pathname
:directory (append (pathname-directory wildcard) (list :wild))
:name nil
:type nil
:defaults wildcard))
#-CCL
(defun directory-pathname-p (p)
"Is the given pathname the name of a directory? This function can
usefully be used to test whether a name returned by LIST-DIRECTORIES
or passed to the function in WALK-DIRECTORY is the name of a directory
in the file system since they always return names in `directory normal
form'."
(flet ((component-present-p (value)
(and value (not (eql value :unspecific)))))
(and
(not (component-present-p (pathname-name p)))
(not (component-present-p (pathname-type p)))
p)))
(defun file-pathname-p (p)
(unless (directory-pathname-p p) p))
;; (pathname-as-directory "foo")
#+sbcl ;otherwise think already defined
(defun pathname-as-directory (name)
"Return a pathname reperesenting the given pathname in
`directory normal form', i.e. with all the name elements in the
directory component and NIL in the name and type components. Can
not be used on wild pathnames because there's not portable way to
convert wildcards in the name and type into a single directory
component. Returns its argument if name and type are both nil or
:unspecific."
(let ((pathname (pathname name)))
(when (wild-pathname-p pathname)
(error "Can't reliably convert wild pathnames."))
(if (not (directory-pathname-p name))
(make-pathname
:directory (append (or (pathname-directory pathname) (list :relative))
(list (file-namestring pathname)))
:name nil
:type nil
:defaults pathname)
pathname)))
#+sbcl ;otherwise think already defined
(defun pathname-as-file (name)
"Return a pathname reperesenting the given pathname in `file form',
i.e. with the name elements in the name and type component. Can't
convert wild pathnames because of problems mapping wild directory
component into name and type components. Returns its argument if
it is already in file form."
(let ((pathname (pathname name)))
(when (wild-pathname-p pathname)
(error "Can't reliably convert wild pathnames."))
(if (directory-pathname-p name)
(let* ((directory (pathname-directory pathname))
(name-and-type (pathname (first (last directory)))))
(make-pathname
:directory (butlast directory)
:name (pathname-name name-and-type)
:type (pathname-type name-and-type)
:defaults pathname))
pathname)))
;; (walk-directory *logs-root* #'pprint :directories t :test #'directory-p)
(defun walk-directory (dirname fn &key directories (test (constantly t)))
"Walk a directory invoking `fn' on each pathname found. If `test' is
supplied fn is invoked only on pathnames for which `test' returns
true. If `directories' is t invokes `test' and `fn' on directory
pathnames as well."
(labels
((walk (name)
(cond
((directory-pathname-p name)
(when (and directories (funcall test name))
(funcall fn name))
(dolist (x (list-directory name)) (walk x)))
((funcall test name) (funcall fn name)))))
(walk (pathname-as-directory dirname))))
(defun directory-p (name)
"Is `name' the name of an existing directory."
(let ((truename (file-exists-p name)))
(and truename (directory-pathname-p name))))
(defun file-p (name)
"Is `name' the name of an existing file, i.e. not a directory."
(let ((truename (file-exists-p name)))
(and truename (file-pathname-p name))))
;"home/local/bank-a-trail/code/web-access/elf-database3a.lisp" 1610 lines --64%--
;
(defun pathname-lessp (pathname1 pathname2)
(string-lessp (princ-to-string pathname1)
(princ-to-string pathname2)))
(defun subdirs-of (dirname &key recursive-p)
(loop
for pathname in (list-directory dirname)
when (directory-p pathname)
collect pathname
into subdirs
finally
(return
(if subdirs
(if recursive-p
(cons dirname
(loop for subdir in (sort subdirs #'pathname-lessp)
collect (let ((sub-subdirs
(subdirs-of subdir
:recursive-p recursive-p)))
(if sub-subdirs
(list subdir sub-subdirs)
subdir))))
(sort subdirs #'pathname-lessp))
(sort subdirs #'pathname-lessp)))))
(defvar *logs-root* "")
(defun recursive-dirs (&optional (base-dir *logs-root*))
(let (pathnames)
(flet ((push-dir (dir)
(push dir pathnames)))
(walk-directory base-dir #'push-dir
:directories t
:test #'directory-p)
(sort pathnames #'pathname-lessp)
)))
;-http://www.koders.com/lisp/fidFB7070D914D164945DCC6128CF2A5307A8C34731.aspx?s=common#L1
(defmacro in-directory ((dir) &body body)
`(progn
(#+sbcl sb-posix:chdir #+cmu unix:unix-chdir #+openmcl ccl:cwd
#+allegro excl:chdir #+lispworks hcl:change-directory ,dir)
,@body))
(defun launch-background-program (directory program &key (args nil))
"Launch a program in a specified directory - not all shell interfaces
or OS's support this"
#+(and allegro (not mswindows))
(multiple-value-bind (in out pid)
(excl:run-shell-command (concat-separated-strings " " (list program) args)
:wait nil
:directory directory)
(declare (ignore in out))
pid)
#+(and sbcl unix)
(in-directory (directory)
(sb-ext:run-program program args :wait nil))
#+cmu
(in-directory (directory)
(ext:run-program program args :wait nil))
#+openmcl
(in-directory (directory)
(ccl:run-program program args :wait nil))
#+lispworks
(funcall #'sys::call-system
(format nil "~a~{ '~a'~} &" program args)
:current-directory directory
:wait nil)
)
(defun kill-background-program (process-handle)
#+(and allegro (not mswindows))
(progn (excl.osi:kill process-handle 9)
(system:reap-os-subprocess :pid process-handle))
#+(and sbcl unix)
(sb-ext:process-kill process-handle 9)
#+openmcl
(ccl:signal-external-process process-handle 9) )
;-
#+sbcl (defun cd (path) (sb-posix:chdir path))
(defun ls (&optional d)
(break2lines
(if (stringp d) (run-ext "ls" d)
(run-ext "ls"))))
;==start=
;(defun head (l) (subseq l 0 4))
;(defun head (l &optional (n 4)) (subseq l 0 n))
(defun head (l &optional (n 4)) (subseq l 0 (min n (len l))))
;(defun tail (l) (last l 4))
;(defun tail (l &optional (n 4)) (last l n))
(defun tail (l &optional (n 4)) (last l (min n (len l))))
(defun last3 (l) (last l 3))
;==> /Users/bobak/Documents/downloads/lang/lsp/ai/ut/mfkb/km/run/two/ut/util-mb.cl <==
;utils collected/written by m.bobak
;sb- specific now, might do it w/o; &/or if want acl specific subsys like agraph, just load km/triple
;(require :sb-posix)
;-gen utils now
(defvar *dbg-ut* nil)
;from ch.cl
(defun numbers (n) ;clips/py has a more general one
(if (eq n 1) (list 1) ;can use phrNum from tsp.cl this time
(append (numbers (- n 1)) (list n))))
;from csv.lsp
(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (fboundp 'parse-number)
(defun parse-number (s)
(with-standard-io-syntax ()
(let* ((*read-eval* nil)
(*read-default-float-format* 'double-float)
(n (read-from-string s)))
(if (numberp n) n))))))
;tsp.cl
(defun remove-nils (l) (remove-if #'null l))
(defun nth+ (ns ls)
"nth from a list vs a single int"
(remove-nils ;assume nils only at end
(mapcar #'(lambda (n) (nth n ls)) ns)))
;
(defun nop (a) a)
;
;pass in keys, so can send: :test #'string-equal, &generlize beyond str2seq
(defun split-str2by (str by) ;can generalize, think there is something already
"str by char get cons"
(when (position by str)
(let ((p (position by str)))
(cons (subseq str 0 p)
(subseq str (+ p 1))))))
(defun last-str2by (str by)
"str from char on"
(let ((p (position by str)))
(when p (subseq str p ))))
(defun first-str2by-end (str by)
"str till char"
(let ((p (positions by str)))
(when p (subseq str 0 (1+ (last_lv p))))))
(defun between-str2by (str by by2)
"between first by and last by2"
(first-str2by-end (last-str2by str by) by2))
(defun last-str2by-end (str by)
(let ((p (positions by str)))
(when p (subseq str (last_lv p)))))
;or for now ;oh could mv let up
#+ignore
(defun split-strs2at (strs by) ;mv let up
(when (position by strs :test #'string-equal)
(let ((p (position by strs :test #'string-equal)))
(cons (apply #'str-cat (subseq strs 0 p))
(apply #'str-cat (subseq strs (+ p 1)))))))
(defun split-strs2at (strs by)
(let ((p (position by strs :test #'string-equal)))
(when p (cons (subseq strs 0 p) (subseq strs (+ p 1))))))
;(defun split-at (seq by)
; (let ((p (position by seq :test #'equal)))
; (when p (list (subseq seq 0 p) (subseq seq (+ p 1))))))
;#+ignore-w-km
(defun split-at (seq by)
(let ((p (position by seq :test #'equal)))
(when p (values (list (subseq seq 0 p) (subseq seq (+ p 1))) p))))
(defun split-at_p (p seq)
(when (< 0 p (len seq))
(list (subseq seq 0 p) (subseq seq (+ p 1)))))
(defun split-nth (p seq)
(when (< 0 p (len seq))
(list (subseq seq 0 p) (nth p seq) (subseq seq (+ p 1)))))
;from lx2.cl
(defun cdr- (cns)
(if (full cns) (cdr cns) ""))
(defun split-second (line &optional (splt #\:))
(cdr- (split-str2by line splt)))
;(split-str2by "C0030705:Patients" #\:) ;("C0030705" . "Patients")
;yes, utl-.lsp's csv-parse-string
;started as oba parsing routines, but breaking out utils
;==> ab.cl <== ;Start using s-query so the xml can change
; (:|obs.common.beans.AnnotationBean| (:|score| "122")
; (:|concept| (:|localConceptID| "CSP/C0006826") (:|preferredName| "cancer")
; (:|synonyms| (:|string| "neoplasm/cancer")) (:|isTopLevel| "false")
; (:|localOntologyID| "CSP")
; (:|localSemanticTypeIDs| (:|string| "T191") (:|string| "T000")))
; ((:|context| :|class| "obs.common.beans.MappingContextBean")
; (:|contextName| "MAPPING") (:|isDirect| "false")
; (:|mappedConceptID| "CST/C0006826") (:|mappingType| "inter-cui")))
; -write some spath like code to find elts by tag, basically an assoc/but not dotted
; I really do NOT like list acessors
; ==I'd really like auto-mapping to CLOS obj/ins, but it is so embedded, I'll still look.
(defun secondt (tv pr)
(when (and (listp pr) (eq (first pr) tv)) (second pr)))
(defun second-t (tv pr &optional (dflt nil))
(if (and (listp pr) (eq (first pr) tv)) (second pr)
dflt))
(defun rest-t (tv pr &optional (dflt nil))
(if (and (listp pr) (eq (first pr) tv)) (rest pr)
dflt))
;=====utl.lsp
(defun fulll (l)
(and (listp l) (> (length l) 0)))
(defun first-lv (lv)
(if (fulll lv) (first lv) lv))
(defun rest-lv (lv)
(if (fulll lv) (rest lv) lv))
(defun second-lv (lv) (if (fulll lv) (second lv) lv))
(defun third-lv (lv) (if (fulll lv) (third lv) lv))
(defun fourth-lv (lv) (if (fulll lv) (fourth lv) lv))
(defun nth-lv (n lv)
(if (fulll lv) (if (>= n (len lv)) (progn (format t "nth-lv:~a ~a" n lv) (last-lv lv))
(nth n lv))
lv))
(defun last-lv (lv)
(if (fulll lv) (last lv) lv))
(defun last_lv (lv) ;so not a list
(first-lv (last-lv lv)))
(defun last_lvr (l)
(let ((lv (last_lv l)))
(if (listp lv) (last_lvr lv)
lv)))
(defun car_lv (lv) (when (consp lv) (car lv)))
(defun car-lv (lv) (if (consp lv) (car lv) lv))
(defun car_eq (l v) (when (consp l) (when (eq (car l) v) l)))
(defun cdr-lv (lv) (if (consp lv) (cdr lv) lv))
;
;(defun assoc-v (k a) (let ((v (assoc k a))) (when (consp v) (cdr v))))
;(defun assoc-v (k a) (let ((v (assoc k a :test #'equal))) (when (consp v) (cdr v))))
(defun assoc-v (k a) (let ((v (assoc k a :test #'equal))) (if (consp v) (cdr v) v))) ;or assoc_v
;mk more gen vers of:
(defun mapcar- (f l) (when (fulll l) (mapcar f l)))
(defun mapcar_ (f l) (if (fulll l) (mapcar f l)
(funcall f l)))
(defun mapcar_2 (f l l2) (if (and (fulll l) (fulll l2)) (mapcar f l l2)
(funcall f l l2)))
;
(defun list+ (ml)
(if (listp ml) ml (list ml)))
;
(defun flat1onlys (l)
"get rid of all (((a)) till just (a)"
(if (and (listp l) (eq (len l) 1) (listp (first-lv l))) (flat1onlys (first-lv l))
l))
(defun first_lv (lv)
(if (fulll lv) (first (flat1onlys lv)) lv))
;
(defun first_lvr (l)
(let ((lv (first_lv l)))
(if (listp lv) (first_lvr lv)
lv)))
(defun first-eqr (l e)
(when (listp l) (eq (first_lvr l) e)))
;
(defun nn (n) (if (numberp n) n 0))
(defun nn> (&rest args) (apply #'> (mapcar #'nn args)))
(defun first-nn (lv) (nn (first-lv lv)))
(defun full (a)
"clips leftover not needed in lsp"
(if (stringp a) (> (length a) 0)
(not (null a))))
(defun nul (a)
(not (full a)))
;=====
(defun str-trim (s)
(string-trim '(#\Space #\Tab #\Newline) s))
(defun intern-trim (s) ;consider: (intern (string-upcase ))
(intern (str-trim s)))
(defun str_trim (s)
(if (stringp s) (str-trim s) s))
(defun safe-trim (s)
(string-trim '( #\( #\) #\tab #\newline #\space #\; #\\) s))
;;; with apologies to christophe rhodes ...
(defun split (string &optional max (ws '(#\Space #\Tab)))
(flet ((is-ws (char) (find char ws)))
(nreverse
(let ((list nil) (start 0) (words 0) end)
(loop
(when (and max (>= words (1- max)))
(return (cons (subseq string start) list)))
(setf end (position-if #'is-ws string :start start))
(push (subseq string start end) list)
(incf words)
(unless end (return list))
(setf start (1+ end)))))))
(defun explode- (string &optional (delimiter #\Space))
(let ((pos (position delimiter string)))
(if (null pos)
(list string)
(cons (subseq string 0 pos)
(explode- (subseq string (1+ pos))
delimiter)))))
(defun explode-2 (string &optional (delimiter #\Space) (offset nil))
(let ((pos (position delimiter string)))
(if (or (null pos) (eq pos 0)) (list string)
(let ((npos (if (integerp offset) (+ pos offset) pos)))
(cons (subseq string 0 npos)
(explode-2 (subseq string (1+ npos))
delimiter offset))))))
(defun str-cat2 (a b)
(format nil "~a~a" a b))
(defun str-cat (&rest args)
(reduce #'str-cat2 args))
;-langband:
(defun strcat (&rest args)
(apply #'concatenate 'string args))
;when you need spaces between
(defun str-cat_2 (a b)
(format nil "~a ~a" a b))
(defun str-cat+ (&rest args)
(reduce #'str-cat_2 args))
;(defun implode-l (l)
; (apply #'strcat (mapcar #'to-str l)))
(defun implode-l (l &optional (insert-spaces t))
(let* ((f (if insert-spaces #'to-str+ #'to-str))
(s (apply #'strcat (mapcar f l))))
(if insert-spaces (str-trim s) s)
))
(defun implode_l (l &optional (insert-spaces t))
(string-downcase (implode-l l insert-spaces)))
(defun sym-cat (&rest args)
;(intern (str-cat @args))
(intern (reduce #'str-cat2 args)))
(defun break2lines (s)
(explode- s #\Newline))
(defun break-by-bar (s)
(explode- s #\|))
;defun split-by (d s) (explode- s :delimeter d)
(defun split-by (d s)
(explode- s d))
(defun split-by-slash (s)
(explode- s #\/))
(defun split-by_ (s)
(explode- s #\_))
(defun rm-commas (s)
(remove #\, s))
(defvar +whitespace-chars+ ;https://github.com/kingcheez/clsql-cheez/blob/master/sql/utils.lisp
'(#\space #\tab #\newline #\return
;; Tested: sbcl unicode, allegrocl, openmcl,clisp use #\no-break_space
;; lispworks uses #\no-break-space
;; sbcl non-unicode doesn't support no break space
;; AllegroCL 8-bit strings don't fail on reading #\no-break_space,
;; but can't represent such a character
;; CMUCL errors when trying to read #\no-break_space
#+(and lispworks unicode) #\no-break-space
#+(or (and sbcl sb-unicode) (and allegro ics) (and clisp i18n)
(and openmcl openmcl-unicode-strings))
#\no-break_space
)
"List of whitespace characters for this lisp implementation.")
(defun trim-commas (s)
(string-trim '(#\, #\Space #\Tab #\Newline +whitespace-chars+) s))
(defun rm-space (s)
(remove +whitespace-chars+ (remove #\space s)))
(defun rm-ws-parens (s)
;(when (full s) (remove-if #'(lambda (x) (member x "( )")) s))
(when (stringp
(if (listp s) (first s) s)) (string-trim '(#\Space #\Tab #\Newline #\( #\)) s)))
;had list, but can't trim everything, or can't break it
; -there are times if 1char long you want to keep it, even make it a char-
(defun rm-star (s) (remove #\* s))
(defun rm-parens (s) (remove #\( (remove #\) s)))
(defun no* (str) (csv-trim2 '( #\*) str)) ;utl
(defun noparens (str) (csv-trim2 '( #\( #\)) str)) ;utl
;either get something 1before the split-by, or just regular explode& filter/remove-if-not prefix ed (
; then make sure paren-strings are combined/collected into one list (no sublists) of strs
;so need prefix-p ;use string= ;fix
(defun prefix-p (pre s) ;prefixp is better below
(and (stringp s) ;(sequence-p s)
(eq 0 (position pre s))))
(defun paren-str-p (s)
(prefix-p #\( s))
;problem is the explode doesn't keep multi word paren-strs together
;could look for postfix-p too, &terms between
;Basically for every input string only want str between the parens, or paren-on
(defun paren_on (s)
"only substrs w/parens"
(remove-if-not #'paren-str-p (explode- s) ;s
)) ;(paren_on "a (b) (c)") ;("(b)" "(c)")
; probably easier to just go back one
; or just add on where needed
(defun set-prefix (pre s)
"prefix if a string"
(if (stringp s) (str-cat pre s)
s))
(defun preparen (s)
"balance out paren-str"
(str_trim
(set-prefix #\( s)
))
(defun paren-on (s)
"ret from paren on in the str"
(let ((l (split-by #\( s)))
;when (listp l) (preparen (rest l)) ;s
(when (listp l) (preparen (second l))
;(when (listp l) (rm-ws-parens (rest l))
)))
;not reall a rm-
(defun rm_comma (s)
(substitute #\Space #\, s))
(defun rm-comma (s)
(substitute #\_ #\, s))
(defun rm-colon (s)
(substitute #\_ #\: s))
(defun rm-dash (s)
(substitute #\Space #\- s))
(defun rm-bslash (s)
(substitute #\Space #\/ s))
(defun underscore (s)
(substitute #\_ #\Space s))
;(defun underscore_ (s) (string-downcase (underscore s)))
(defun underscore_ (s-)
(let ((s (if (symbolp s-) (symbol-name s-)
s-)))
(string-downcase (underscore s))))
(defun under_ (s) (string-downcase (underscore s)))
(defun str-cat_ (a) (under_ (str-cat a))) ;try
(defun str-cat_l (l) (str-cat_ (implode-l l)))
(defun has-space-p (s)
(find #\Space s))
(defun rm-pd (s) "rm post -dashed like -pos" (butlast (explode- (rm-dash s))))
(defun under-pd (s) "under_ of all but -pos" (str-cat_l (rm-pd s)))
(defun under-pd-l (l) (str-cat_l (mapcar- #'rm-pd l))) ;could overload above
(defun rm-underscore (s)
(substitute #\Space #\_ s))
(defun hyphenate (s)
(substitute #\- #\Space s))
(defun under2hyphen (s)
(substitute #\- #\_ s))
(defun under2sp (s)
(substitute #\Space #\_ s))
(defun hyphen2under (s)
(substitute #\_ #\- s))
(defun replace-commas (s)
(substitute #\; #\, s))
(defun slash2hyphen (s)
(substitute #\- #\\ s))
(defun all2hyphen (s cl)
"all in changeList2hypens"
(if (not (fulll cl)) s
(all2hyphen
(substitute #\- (first cl) s)
(rest cl))))
(defun plusify-str (s)
(substitute #\+ #\Space s))
(defun no-retlines (s)
(substitute #\Space #\Newline s))
;(defun len (l) (when (listp l) (length l)))
;(defun len (l) (when (or (listp l) (stringp l)) (length l)))
;(defun len (l) (if (or (listp l) (stringp l)) (length l)
; (when (arrayp l) (first (array-dimensions l)))))
(defun len (l) (typecase l
(list (length l))
(string (length l))
(symbol (length (symbol-name l)))
(array (first (array-dimensions l)))))
(defun nnlen (l)
"0 vs nil, if can't get length"
(nn (len l)))
(defun len= (l n) (when (listp l) (eq (length l) n)))
(defun tree-size (tree) ;http://tehran.lain.pl/stuff/diff-sexp.lisp
"Computes the number of atoms contained in TREE."
(if (atom tree)
1
(reduce #'+ tree :key #'tree-size)))
;------
(defun lexemep (s) (or (stringp s) (symbolp s)))
(defun lens1 (s) (if (lexemep s) 1 (len s)))
;------
(defun lens (l)
(mapcar #'len l))
;------
(defun substr (txt from to)
"subseq for str w/test"
(when (>= (length txt) to from 0) (subseq txt from to)))
(defun substr- (txt from to)
;(substr txt (1- from) (1- to)) ;should be this
(when (full txt)
(substr txt (1- from) to)
))
;==was tree-depth but already in km
(defun tree_depth (tree)
(cond ((atom tree) 0)
(t (1+ (reduce #'max (mapcar #'tree-depth tree))))))
(defun list+2depth (a d)
(if (<= d 0) a
(list+2depth (list a) (1- d))))
(defun list2depth (a wd) ;only adds to wd, could flat-1/flat1 the other way, &/or start w/flat1onlys
(let ((pd (tree_depth a)))
(list+2depth a (- wd pd))))
(defun list++ (ml &optional (assure-depth 1)) ;starts out just like list+ but can modify
;(if (listp ml) ml (list ml))
(let ((td (tree_depth ml)))
(if (< td assure-depth) (list+2depth ml (- assure-depth td))
ml)))
(defun list+2 (ml) (list++ ml 2))
(defun tree-stats (tree)
;(format t "~&width:~a depth:~a size:~a" (len tree) (tree-depth tree) (tree-size tree))
(let ((wid (len tree)) (dep (tree-depth tree)) (siz (tree-size tree)))
(format t "~&width:~a depth:~a size:~a" wid dep siz)
(if (> siz (* wid dep)) (format t " > ~a " (* wid dep)))
))
;=====
(defun str_cat (&rest args)
(apply #'concatenate 'simple-string args))
;rest already above
;(defun str-cat2 (a b)
; (format nil "~a~a" a b))
;(defun str-cat (&rest args)
; (reduce #'str-cat2 args))
;=====
;-in utl.lsp now
;CL-USER(7): (read-delimited-list #\, (make-string-input-stream "1,2,3"))
;(1) ;see o13a for more
;--
;(with-input-from-string (s "6") (read s)) -> 6
;--
;(parse-integer "word" :junk-allowed t)
;--
(defun alpha-start (str)
"does it start w/an alpha"
(alpha-char-p (char str 0))
)
(defun has-alpha-p (str)
(alpha-start str);for now
)
;--
;it might be better to alter explode str, to have numbers go to numbers; as easier to look@separated?
;find-if #'alpha-char-p ;but don't know if it fits in there?
;--
(defun num-str (numstr)
(let ((n (parse-integer numstr :junk-allowed t)))
(if n n numstr))
)
(defun numstr (numstr)
"get num from a str"
(if (equal numstr "") 0
(if (or (numberp numstr) (alpha-start numstr) ) numstr
(read-from-string (remove #\: numstr)) ;(num-str numstr)
)
))
;--
(defun has-date-p (s) (len-gt (positions #\: s) 1))
(defun numstr- (s)
(if (has-date-p s) (prs-univ-time- s) (numstr s)))
;--
;I'd like to be able to rm a : at the end of what is read..
;--
;whish I could READ-FROM-STRING w/a format ;look@ make-string-input-stream
;;;just USE: READ-DELIMITED-LIST ...!!!but needs a stream, still
;-garnet
;;; Read and return the numbers at the end of a line on stream bitstream
;;;
(defun get-nums (bitstream) ;garnet/opal/mac.lisp
(do ((ch (peek-char t bitstream) (peek-char t bitstream)))
((digit-char-p ch))
(read-char bitstream))
(parse-integer (read-line bitstream)))
;-langband: ;already above
;(defun strcat (&rest args)
; (apply #'concatenate 'string args))
;----- csv.lisp simplification
(defun csv-trim (whitespace string)
"Trim the string argument from the whitespace."
(let ((clean (string-trim whitespace string)))
(if (zerop (length clean)) nil clean))
)
(defun csv-trim2 (whitespace string)
(let ((c2 (csv-trim whitespace string)))
(if c2 c2 " ")))
(defvar *punct* "[]();.")
(defvar *punct2* "[]();., ")
(defun punct-p (str)
(position (aref str 0) *punct*))
(defun punctp (str)
(and (eq (length str) 1) (not (alphanumericp (aref str 0)))))
(defvar +whitespace+ " ")
;(defvar +whitespace+ " \0") ;mmtx tagger puts out \0's ;but it's dangerous
(defun csv-parse-string (string &key (separator #\,) (whitespace +whitespace+))
"Parse a string, returning a vector of strings."
(loop :with num = (count separator string :test #'char=)
:with res = (make-array (1+ num))
:for ii :from 0 :to num
:for beg = 0 :then (1+ end)
:for end = (or (position separator string :test #'char= :start beg)
(length string))
:do (setf (aref res ii)
(when (> end beg) ; otherwise NIL = missing
(csv-trim whitespace (subseq string beg end))))
:finally (return res)))
;---(read-from-string " 1 3 5" t nil :start 2)
;==new==
;defun csv-parse-str (string &key (separator #\t) (whitespace +whitespace+))
(defun csv-parse-str (string &key (separator #\Tab) (whitespace +whitespace+))
"Parse a string, returning a vector of strings."
(loop :with num = (count separator string :test #'char=)
:with res = (make-array (1+ num))
:for ii :from 0 :to num
:for beg = 0 :then (1+ end)
:for end = (or (position separator string :test #'char= :start beg)
(length string))
:do (setf (aref res ii)
(when (> end beg) ; otherwise NIL = missing
(csv-trim whitespace (subseq string beg end))))
:finally (return res)))
;==
;my try
(defun read-from-csv-str (str &key (start 0) (separator #\,))
(if (>= start (length str)) nil
(let ((pn (position separator str)))
(if (not pn) nil
(cons (read-from-string str t nil :start start)
(read-from-csv-str str :start (+ start pn))))))
)
;--from clhp:
(defmacro if-bind ((&rest bindings) test if else)
"An IF wrapped in a LET"
`(let (,@bindings) (if ,test ,if ,else))
)
(defmacro explode-string (string)
"Converts a string to a list of chars, this is an aux function used
for string processing.
ex: (EXPLODE-STRING \"Hello\") --> (#\H #\e #\l #\l #\o)"
`(concatenate 'list ,string)
)
(defun implode-string (char-list)
"Converts EXPLODEd CHAR-LIST into string, used as an aux function
for string processing.
ex: (IMPLODE-STRING '(#\H #\e #\l #\l #\o)) --> \"Hello\"
(IMPLODE-STRING (EXPLODE-STRING \"Hello\")) --> \"Hello\""
(coerce char-list 'string) ;maybe allow other types?
)
(defun implode- (cl)
"kludge"
(if (listp cl) (implode-string cl)
(numstr cl) ;(eval cl) ;need to get it to turn "1"->1
)
)
;; ex: ;this is the explode that I'm used to, but explode-str w/opt #\Space does the same
;; (mapcar #'implode-string
;; (split-char-list #\Space
;; (explode-string "In God We Trust" ))) -->
;; ("In" "God" "We" "Trust")