www.delorie.com/archives/browse.cgi   search  
Mail Archives: geda-user/2016/07/19/04:02:05

X-Authentication-Warning: delorie.com: mail set sender to geda-user-bounces using -f
X-Recipient: geda-user AT delorie DOT com
X-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20120113;
h=mime-version:from:date:message-id:subject:to;
bh=2zwhFOW9Mm3X1R3e5l+2mSGPrKT/gBeSFrizIMcCyQY=;
b=b5Tc+ibeUlZl9BQlgWtY1hOP49PGn6j5JEEg5JAHMMU85LhvPUqIvwpPpHlMc5+EwH
Hp9FPMTvO6bHNKII5wuv6+LeJq2yymtWWv4VYl01PAfoJTldY9jSJTI26Zh26V+sTp2K
TI2vBHMgko+v9GfNNb4qHqxhlqXAuRsglX/z0jI952CsmeNvOIACHhbHsbSkom65VFY0
3Cl96R/Wj18BMPEEQMkjh+EhQwTyBtbRQNO3vz4KryerbbgY1oT39PCpX3X/lA6/D86y
DCnn2rrP6A9+XLVnd/vCZZeE/LDyVfY5glrEFw7FTJaIHQPOO4UCo2y1yRQi9sZkjeuN
3GJg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20130820;
h=x-gm-message-state:mime-version:from:date:message-id:subject:to;
bh=2zwhFOW9Mm3X1R3e5l+2mSGPrKT/gBeSFrizIMcCyQY=;
b=kbZJem2K6Td/ZkPGKh9+Fz2nac0oaXVLU1KzpMgf9nqI8kBUoSm5QOSxEhW0T3oOtK
BgFpFVpTKaGXIQ9YdnSQ6DJnWckqhCw1n7j2tgPORLETIqQosHIaPLjvN5CcDtoM2UEO
wDSP5itlHo7ZKsIZhQmgabFcopM7vXOpYwJji8HzdV/Lv2fhqyVCXUbV2EBKFZTZ39ku
qgzbLCXqNMxczedBiE8fhJpuck8OXD4Lp/LW4hr+FI8tV5HGqvEfUZ3tFfht1K0HOqFW
my7+5swysXO6XA2gVaMo3kQDXm3uO7IPGobOYAsbPmQsUfEoaQD0ODIyphhKr1Zu7FF6
nldA==
X-Gm-Message-State: ALyK8tJITYTWwIYo3D7JXvLlWQcKzqzbpYJZk7wzUSmtr2YN9cXNf7ZoKsWwa8EJtoHMorsZ5Cv4Ar3x7LAzSA==
X-Received: by 10.31.166.20 with SMTP id p20mr19762723vke.2.1468915199475;
Tue, 19 Jul 2016 00:59:59 -0700 (PDT)
MIME-Version: 1.0
From: "Vladimir Zhbanov (vzhbanov AT gmail DOT com) [via geda-user AT delorie DOT com]" <geda-user AT delorie DOT com>
Date: Tue, 19 Jul 2016 10:59:58 +0300
Message-ID: <CAMvDHVAFAZieeveBynAkYRgnfyTYM+27cXVzfd9277aSOASNZA@mail.gmail.com>
Subject: [geda-user] Easy sophisticated partlist creation
To: geda-user <geda-user AT delorie DOT com>
Note-from-DJ: This may be spam
Reply-To: geda-user AT delorie DOT com

--001a11416d80ab95460537f8787e
Content-Type: text/plain; charset=UTF-8

Hi dear gEDA users,

Inspired by discussion on the list about half a year ago I decided
to write a Scheme function for creating sophisticated
partlists. The discussion started due to a bug in the backend
partslist3 reported by Karl Hammar (thank you, Karl!). It took a
while to understand what I want and how to do this, but now you
can try to write a small custom partlist backend yourself.

Now, a little introduction.

I have started rewriting things as reusable Scheme modules
accompanied with unit testing provided in the standard Scheme unit
testing framework module (srfi srfi-64). Look at the last couple
of patches in the geda-gaf repository, if you want to know more.

-------------------------------->8--------------------------------
$ gnetlist -i test.sch
...

Enter `,help' for help.
gnetlist> ,use (gnetlist partlist)
gnetlist> (help partlist->string)
`partlist->string' is a procedure in the (gnetlist partlist) module.

Takes PART-LIST  and outputs a string representing a
table of attribute values of the list. The following optional
arguments may be used:

  GROUP-BY is a name of the attribute by which the part list is
  grouped.

  SORT-ORDER may be an alist consisting of attribute names with
  corresponding sorting functions, or just a list of attribute names
  in which case the parts are sorted using default functions defined
  for corresponding attributes. If no sorting function is defined
  for an attribute name, the case insenstive string sorting function
  string<? is used. No sorting is carried out for attribute names
  missing in the list. The priority of sorting lowers from the first
  element to the last, that is, last attributes are taken into
  account only if all previous attributes are equal.

  OUTPUT-ORDER is a list of attribute names specifying the order in
  which the part attributes are output.

  HEADER is a text which is output without any change before
  the attribute table contents.

  FOOTER is a text which is output without any change after the
  attribute table contents.

  PREPEND-NAMES? is predicate specifying if the first line
  of the table must be the list of output attribute names.

  QUANTITY-HEADER is a text which is output for quantity column if
  PREPEND-NAMES? is not #f.

  REDUCE? is a predicate specifying if lists of grouped values must
  be reduced so that attribute values in series contain only their
  first and last values, e.g. the list of strings "R1", "R2",
  and "R3" can be transformed to "R1-R3".

  ROW-SEPARATOR is a separator string for table rows. Default
  value is "\n" (newline).

  COLUMN-SEPARATOR is a separator string for table
  columns. Default value is "\t" (tabulation).

  GROUP-SEPARATOR is a separator string for group members. Default
  value is ", ".

  SUBGROUP-SEPARATOR is like GROUP-SEPARATOR, but it is used
  between first and last elements of each subgroup (if any) of
  reduced groups if REDUCE? is not #f. Default value is "-".

  TRANSPOSE? is a predicate used to specify that the resulting
  table must be transposed, that is, part attributes are output in
  columns rather than rows.

  LETTER-CASE is an attribute value case transformation alist of
  the form
    '((NAME . VALUE) ...)
  where NAME is an attribute name and VALUE may be one of 'upper,
  'lower, or 'smart. The first two values mean that letters are to
  be transformed to upper or lower case, accordingly. The last one
  is used for special case transformations where an appropriate
  transformation function is seached for by attribute name in an
  internal function table.

  REMOVE is an alist of attributes of the form
    '((NAME . VALUE) ...)
  where NAME is a symbol and VALUE is a string, and both define
  the attribute which, being found on a part, tells that all
  attributes of the part are to be removed from the output. Such
  filtering is carried out after letter case modification.
--------------------------------8<--------------------------------

As you can see, the new function's name is partlist->string.
There are also two comparison functions in the module (gnetlist
attrib compare): refdes<? and value<?. Use gnetlist as above to
learn more of them.

Now look at the code of the backends partslist1, partslist2, and
partslist3 rewritten using these new functions. Simple, huh?
Unit tests can give you a hint on how to create your own custom
backend. Say, you want to output part list using LaTeX longtable
environment. Let's try to write it.

0) Invoke needed modules:
--------------------------------8<--------------------------------
(use-modules (gnetlist partlist)
             (gnetlist partlist common))
-------------------------------->8--------------------------------

1) Define header (later you can read it from a file):
--------------------------------8<--------------------------------
(define document-header "\\documentclass[a4paper,11pt]{letter}
\\usepackage[utf8x]{inputenc}
\\usepackage{lscape}
\\usepackage{longtable}

\\begin{document}
\\pagestyle{empty}
\\noindent\\begin{longtable}{p{.3\\linewidth}|p{.3\\linewidth}|p{.4\\linewidth}}
\\hline
")
-------------------------------->8--------------------------------

2) Define footer:
--------------------------------8<--------------------------------
(define document-footer "
\\end{longtable}

\\end{document}
")
-------------------------------->8--------------------------------

3) Define the function itself:
--------------------------------8<--------------------------------
(define (custom-partlist output-filename)
  (display
   (partlist->string
    (make-partlist '(device value footprint refdes))
    #:group-by 'refdes
    #:sort-order '(refdes footprint device)
    #:output-order '(device footprint refdes)
    #:header document-header
    #:footer document-footer
    #:prepend-names? #f
    #:reduce? #t
    #:row-separator " \\\\\n"
    #:column-separator " & "
    #:group-separator "; "
    #:subgroup-separator "--"
    #:transpose? #f
    )
   (gnetlist:output-port output-filename)))
-------------------------------->8--------------------------------

Now create a directory for your gnetlist backends, say ~/custom,
save the file as ~/custom/gnet-custom-partlist.scm and give it a try:

--------------------------------8<--------------------------------
$ cd my-project-directory
$ gnetlist -L ~/custom/  -g custom-partlist -o "-" test.sch
\documentclass[a4paper,11pt]{letter}
\usepackage[utf8x]{inputenc}
\usepackage{lscape}
\usepackage{longtable}

\begin{document}
\pagestyle{empty}
\noindent\begin{longtable}{p{.3\linewidth}|p{.3\linewidth}|p{.4\linewidth}}
\hline
resistor & m1608_a.fp & R7 \\
Resistor & m1608_a.fp & R8; Rb1 \\
resistor & m1608_a.fp & R13
\end{longtable}

\end{document}
-------------------------------->8--------------------------------

Use `-o partlist.tex' to redirect output to a file, then pdflatex,
and that's all. Your PDF is ready.

Ah, stop. Why resistors are not properly grouped?! Obviously,
their devices have different cases, though I don't understand yet,
why two lowercase 'resistor's aren't grouped?

Let's add the keyword letter-case:
--------------------------------8<--------------------------------
    ...
    #:transpose? #f
      #:letter-case '((device . smart))
    )
    ...
-------------------------------->8--------------------------------

Now we have (I keep only important part removing header and footer):
--------------------------------8<--------------------------------
RESISTOR & m1608_a.fp & R7 \\
RESISTOR & m1608_a.fp & R8; Rb1 \\
RESISTOR & m1608_a.fp & R13
-------------------------------->8--------------------------------

Hey, they aren't grouped as I wanted?!?

Ah, I see, I use 'value' here
--------------------------------8<--------------------------------
    (make-partlist '(device value footprint refdes))
-------------------------------->8--------------------------------
but don't output it.  OK, let's add it

--------------------------------8<--------------------------------
    #:sort-order '(footprint device refdes value)
    #:output-order '(device footprint refdes value)
-------------------------------->8--------------------------------
If you don't add it to #:sort-order, it will throw an error.

Now we have:
--------------------------------8<--------------------------------
RESISTOR & m1608_a.fp & R7 & 330 \\
RESISTOR & m1608_a.fp & R8; Rb1 & 10k \\
RESISTOR & m1608_a.fp & R13 & 1k
-------------------------------->8--------------------------------

OK, now I see why they are different. Let's remove 'value' all
over and try again:
--------------------------------8<--------------------------------
RESISTOR & m1608_a.fp & R7; R8; R13; Rb1
-------------------------------->8--------------------------------

Hurray! This is what I wanted!

OK, output it to a file and make a pdf file:
--------------------------------8<--------------------------------
$ gnetlist -L ~/custom/ -g custom-partlist -o partlist.tex test.sch
$ pdflatex partlist.tex
...
! Missing $ inserted.
<inserted text>
                $
l.10 RESISTOR & m1608_
                      a.fp & R7; R8; R13; Rb1
?
-------------------------------->8--------------------------------

Brr, what's wrong?
Ah, I see, underscore is a special symbol in LaTeX and must be
escaped. Then we need the module (ice-9 regex) and
substitute its function 'regexp-substitute/global' for
'display'. It has another order of arguments, and their quantity,
so the main function slightly changes.
--------------------------------8<--------------------------------
v(define (custom-partlist output-filename)
  (regexp-substitute/global
   (gnetlist:output-port output-filename) "_"
   (partlist->string
    ... skip keywords here for clarity
    )
   'pre "\\_" 'post))
-------------------------------->8--------------------------------

Yes, I just escaped underscores for LaTeX, and escaped the
backslash itself for Scheme.

Now, do some cosmetic changes (add \hline at the end of the output
table) and run gnetlist and pdflatex once again.

The resulting backend is attached.
Enjoy!

-- 
  Vladimir

--001a11416d80ab95460537f8787e
Content-Type: application/octet-stream; name="gnet-custom-partlist.scm"
Content-Disposition: attachment; filename="gnet-custom-partlist.scm"
Content-Transfer-Encoding: base64
X-Attachment-Id: file0

Cih1c2UtbW9kdWxlcyAoZ25ldGxpc3QgcGFydGxpc3QpCiAgICAgICAgICAgICAoZ25ldGxpc3Qg
cGFydGxpc3QgY29tbW9uKQogICAgICAgICAgICAgKGljZS05IHJlZ2V4KSkKCihkZWZpbmUgZG9j
dW1lbnQtaGVhZGVyICJcXGRvY3VtZW50Y2xhc3NbYTRwYXBlciwxMXB0XXtsZXR0ZXJ9ClxcdXNl
cGFja2FnZVt1dGY4eF17aW5wdXRlbmN9ClxcdXNlcGFja2FnZXtsc2NhcGV9ClxcdXNlcGFja2Fn
ZXtsb25ndGFibGV9CgpcXGJlZ2lue2RvY3VtZW50fQpcXHBhZ2VzdHlsZXtlbXB0eX0KXFxub2lu
ZGVudFxcYmVnaW57bG9uZ3RhYmxlfXtwey4zXFxsaW5ld2lkdGh9fHB7LjNcXGxpbmV3aWR0aH18
cHsuNFxcbGluZXdpZHRofX0KXFxobGluZQoiKQoKKGRlZmluZSBkb2N1bWVudC1mb290ZXIgIiBc
XFxcXG4KXFxobGluZQpcXGVuZHtsb25ndGFibGV9CgpcXGVuZHtkb2N1bWVudH0KIikKCihkZWZp
bmUgKGN1c3RvbS1wYXJ0bGlzdCBvdXRwdXQtZmlsZW5hbWUpCiAgKHJlZ2V4cC1zdWJzdGl0dXRl
L2dsb2JhbAogICAoZ25ldGxpc3Q6b3V0cHV0LXBvcnQgb3V0cHV0LWZpbGVuYW1lKSAiXyIKICAg
KHBhcnRsaXN0LT5zdHJpbmcKICAgIChtYWtlLXBhcnRsaXN0ICcoZGV2aWNlIGZvb3RwcmludCBy
ZWZkZXMpKQogICAgIzpncm91cC1ieSAncmVmZGVzCiAgICAjOnNvcnQtb3JkZXIgJyhmb290cHJp
bnQgZGV2aWNlIHJlZmRlcykKICAgICM6b3V0cHV0LW9yZGVyICcoZGV2aWNlIGZvb3RwcmludCBy
ZWZkZXMpCiAgICAjOmhlYWRlciBkb2N1bWVudC1oZWFkZXIKICAgICM6Zm9vdGVyIGRvY3VtZW50
LWZvb3RlcgogICAgIzpwcmVwZW5kLW5hbWVzPyAjZgogICAgIzpyZWR1Y2U/ICN0CiAgICAjOnJv
dy1zZXBhcmF0b3IgIiBcXFxcXG4iCiAgICAjOmNvbHVtbi1zZXBhcmF0b3IgIiAmICIKICAgICM6
Z3JvdXAtc2VwYXJhdG9yICI7ICIKICAgICM6c3ViZ3JvdXAtc2VwYXJhdG9yICItLSIKICAgICM6
dHJhbnNwb3NlPyAjZgogICAgIzpsZXR0ZXItY2FzZSAnKChkZXZpY2UgLiBzbWFydCkpCiAgICAp
CiAgICdwcmUgIlxcXyIgJ3Bvc3QpKQo=
--001a11416d80ab95460537f8787e--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019