Browse Source

Add abakus

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/abakus@1071969 283d02a7-25f6-0310-bc7c-ecb5cbfe19
tags/v3.5.13
tpearson 9 years ago
commit
8bec1dda93
61 changed files with 13750 additions and 0 deletions
  1. 1
    0
      AUTHORS
  2. 341
    0
      COPYING
  3. 183
    0
      README
  4. 36
    0
      SConstruct
  5. 178
    0
      bksys/abakus.py
  6. 498
    0
      bksys/generic.py
  7. 43
    0
      bksys/help.py
  8. 820
    0
      bksys/kde.py
  9. BIN
      bksys/scons-mini.tar.bz2
  10. 6
    0
      config.h
  11. 164
    0
      configure
  12. 12
    0
      doc/en/SConscript
  13. BIN
      doc/en/abakus-degrees-mode.png
  14. BIN
      doc/en/abakus-dnd.png
  15. BIN
      doc/en/abakus-result.png
  16. 463
    0
      doc/en/index.docbook
  17. BIN
      doc/en/kcalc-degrees-mode.png
  18. BIN
      doc/en/kcalc-fifty.png
  19. BIN
      doc/en/kcalc-result.png
  20. BIN
      doc/en/kcalc-sine.png
  21. BIN
      doc/en/kcalc-three.png
  22. 81
    0
      src/SConscript
  23. 74
    0
      src/abakus.cpp
  24. 38
    0
      src/abakus.desktop
  25. 22
    0
      src/abakuscommon.h
  26. 232
    0
      src/abakuslistview.cpp
  27. 147
    0
      src/abakuslistview.h
  28. 35
    0
      src/abakusui.rc
  29. 47
    0
      src/dcopIface.h
  30. 87
    0
      src/dragsupport.cpp
  31. 33
    0
      src/dragsupport.h
  32. 892
    0
      src/editor.cpp
  33. 131
    0
      src/editor.h
  34. 261
    0
      src/evaluator.cpp
  35. 131
    0
      src/evaluator.h
  36. 298
    0
      src/function.cpp
  37. 122
    0
      src/function.h
  38. BIN
      src/hi64-app-abakus.png
  39. 1797
    0
      src/hmath.cpp
  40. 359
    0
      src/hmath.h
  41. 223
    0
      src/lexer.ll
  42. 825
    0
      src/mainwindow.cpp
  43. 135
    0
      src/mainwindow.h
  44. 419
    0
      src/node.cpp
  45. 219
    0
      src/node.h
  46. 1809
    0
      src/number.c
  47. 169
    0
      src/number.h
  48. 205
    0
      src/numerictypes.cpp
  49. 693
    0
      src/numerictypes.h
  50. 386
    0
      src/parser.yy
  51. 33
    0
      src/result.cpp
  52. 77
    0
      src/result.h
  53. 149
    0
      src/resultlistview.cpp
  54. 64
    0
      src/resultlistview.h
  55. 135
    0
      src/resultlistviewtext.cpp
  56. 70
    0
      src/resultlistviewtext.h
  57. 267
    0
      src/rpnmuncher.cpp
  58. 44
    0
      src/rpnmuncher.h
  59. 122
    0
      src/sharedptr.h
  60. 105
    0
      src/valuemanager.cpp
  61. 69
    0
      src/valuemanager.h

+ 1
- 0
AUTHORS View File

@@ -0,0 +1 @@
1
+Michael Pyne <michael.pyne@kdemail.net>

+ 341
- 0
COPYING View File

@@ -0,0 +1,341 @@
1
+			
2
+		    GNU GENERAL PUBLIC LICENSE
3
+		       Version 2, June 1991
4
+
5
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
6
+               59 Temple Place, Suite 330, Boston, MA  02110-1301  USA
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+			    Preamble
11
+
12
+  The licenses for most software are designed to take away your
13
+freedom to share and change it.  By contrast, the GNU General Public
14
+License is intended to guarantee your freedom to share and change free
15
+software--to make sure the software is free for all its users.  This
16
+General Public License applies to most of the Free Software
17
+Foundation's software and to any other program whose authors commit to
18
+using it.  (Some other Free Software Foundation software is covered by
19
+the GNU Library General Public License instead.)  You can apply it to
20
+your programs, too.
21
+
22
+  When we speak of free software, we are referring to freedom, not
23
+price.  Our General Public Licenses are designed to make sure that you
24
+have the freedom to distribute copies of free software (and charge for
25
+this service if you wish), that you receive source code or can get it
26
+if you want it, that you can change the software or use pieces of it
27
+in new free programs; and that you know you can do these things.
28
+
29
+  To protect your rights, we need to make restrictions that forbid
30
+anyone to deny you these rights or to ask you to surrender the rights.
31
+These restrictions translate to certain responsibilities for you if you
32
+distribute copies of the software, or if you modify it.
33
+
34
+  For example, if you distribute copies of such a program, whether
35
+gratis or for a fee, you must give the recipients all the rights that
36
+you have.  You must make sure that they, too, receive or can get the
37
+source code.  And you must show them these terms so they know their
38
+rights.
39
+
40
+  We protect your rights with two steps: (1) copyright the software, and
41
+(2) offer you this license which gives you legal permission to copy,
42
+distribute and/or modify the software.
43
+
44
+  Also, for each author's protection and ours, we want to make certain
45
+that everyone understands that there is no warranty for this free
46
+software.  If the software is modified by someone else and passed on, we
47
+want its recipients to know that what they have is not the original, so
48
+that any problems introduced by others will not reflect on the original
49
+authors' reputations.
50
+
51
+  Finally, any free program is threatened constantly by software
52
+patents.  We wish to avoid the danger that redistributors of a free
53
+program will individually obtain patent licenses, in effect making the
54
+program proprietary.  To prevent this, we have made it clear that any
55
+patent must be licensed for everyone's free use or not licensed at all.
56
+
57
+  The precise terms and conditions for copying, distribution and
58
+modification follow.
59
+
60
+		    GNU GENERAL PUBLIC LICENSE
61
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
+
63
+  0. This License applies to any program or other work which contains
64
+a notice placed by the copyright holder saying it may be distributed
65
+under the terms of this General Public License.  The "Program", below,
66
+refers to any such program or work, and a "work based on the Program"
67
+means either the Program or any derivative work under copyright law:
68
+that is to say, a work containing the Program or a portion of it,
69
+either verbatim or with modifications and/or translated into another
70
+language.  (Hereinafter, translation is included without limitation in
71
+the term "modification".)  Each licensee is addressed as "you".
72
+
73
+Activities other than copying, distribution and modification are not
74
+covered by this License; they are outside its scope.  The act of
75
+running the Program is not restricted, and the output from the Program
76
+is covered only if its contents constitute a work based on the
77
+Program (independent of having been made by running the Program).
78
+Whether that is true depends on what the Program does.
79
+
80
+  1. You may copy and distribute verbatim copies of the Program's
81
+source code as you receive it, in any medium, provided that you
82
+conspicuously and appropriately publish on each copy an appropriate
83
+copyright notice and disclaimer of warranty; keep intact all the
84
+notices that refer to this License and to the absence of any warranty;
85
+and give any other recipients of the Program a copy of this License
86
+along with the Program.
87
+
88
+You may charge a fee for the physical act of transferring a copy, and
89
+you may at your option offer warranty protection in exchange for a fee.
90
+
91
+  2. You may modify your copy or copies of the Program or any portion
92
+of it, thus forming a work based on the Program, and copy and
93
+distribute such modifications or work under the terms of Section 1
94
+above, provided that you also meet all of these conditions:
95
+
96
+    a) You must cause the modified files to carry prominent notices
97
+    stating that you changed the files and the date of any change.
98
+
99
+    b) You must cause any work that you distribute or publish, that in
100
+    whole or in part contains or is derived from the Program or any
101
+    part thereof, to be licensed as a whole at no charge to all third
102
+    parties under the terms of this License.
103
+
104
+    c) If the modified program normally reads commands interactively
105
+    when run, you must cause it, when started running for such
106
+    interactive use in the most ordinary way, to print or display an
107
+    announcement including an appropriate copyright notice and a
108
+    notice that there is no warranty (or else, saying that you provide
109
+    a warranty) and that users may redistribute the program under
110
+    these conditions, and telling the user how to view a copy of this
111
+    License.  (Exception: if the Program itself is interactive but
112
+    does not normally print such an announcement, your work based on
113
+    the Program is not required to print an announcement.)
114
+
115
+These requirements apply to the modified work as a whole.  If
116
+identifiable sections of that work are not derived from the Program,
117
+and can be reasonably considered independent and separate works in
118
+themselves, then this License, and its terms, do not apply to those
119
+sections when you distribute them as separate works.  But when you
120
+distribute the same sections as part of a whole which is a work based
121
+on the Program, the distribution of the whole must be on the terms of
122
+this License, whose permissions for other licensees extend to the
123
+entire whole, and thus to each and every part regardless of who wrote it.
124
+
125
+Thus, it is not the intent of this section to claim rights or contest
126
+your rights to work written entirely by you; rather, the intent is to
127
+exercise the right to control the distribution of derivative or
128
+collective works based on the Program.
129
+
130
+In addition, mere aggregation of another work not based on the Program
131
+with the Program (or with a work based on the Program) on a volume of
132
+a storage or distribution medium does not bring the other work under
133
+the scope of this License.
134
+
135
+  3. You may copy and distribute the Program (or a work based on it,
136
+under Section 2) in object code or executable form under the terms of
137
+Sections 1 and 2 above provided that you also do one of the following:
138
+
139
+    a) Accompany it with the complete corresponding machine-readable
140
+    source code, which must be distributed under the terms of Sections
141
+    1 and 2 above on a medium customarily used for software interchange; or,
142
+
143
+    b) Accompany it with a written offer, valid for at least three
144
+    years, to give any third party, for a charge no more than your
145
+    cost of physically performing source distribution, a complete
146
+    machine-readable copy of the corresponding source code, to be
147
+    distributed under the terms of Sections 1 and 2 above on a medium
148
+    customarily used for software interchange; or,
149
+
150
+    c) Accompany it with the information you received as to the offer
151
+    to distribute corresponding source code.  (This alternative is
152
+    allowed only for noncommercial distribution and only if you
153
+    received the program in object code or executable form with such
154
+    an offer, in accord with Subsection b above.)
155
+
156
+The source code for a work means the preferred form of the work for
157
+making modifications to it.  For an executable work, complete source
158
+code means all the source code for all modules it contains, plus any
159
+associated interface definition files, plus the scripts used to
160
+control compilation and installation of the executable.  However, as a
161
+special exception, the source code distributed need not include
162
+anything that is normally distributed (in either source or binary
163
+form) with the major components (compiler, kernel, and so on) of the
164
+operating system on which the executable runs, unless that component
165
+itself accompanies the executable.
166
+
167
+If distribution of executable or object code is made by offering
168
+access to copy from a designated place, then offering equivalent
169
+access to copy the source code from the same place counts as
170
+distribution of the source code, even though third parties are not
171
+compelled to copy the source along with the object code.
172
+
173
+  4. You may not copy, modify, sublicense, or distribute the Program
174
+except as expressly provided under this License.  Any attempt
175
+otherwise to copy, modify, sublicense or distribute the Program is
176
+void, and will automatically terminate your rights under this License.
177
+However, parties who have received copies, or rights, from you under
178
+this License will not have their licenses terminated so long as such
179
+parties remain in full compliance.
180
+
181
+  5. You are not required to accept this License, since you have not
182
+signed it.  However, nothing else grants you permission to modify or
183
+distribute the Program or its derivative works.  These actions are
184
+prohibited by law if you do not accept this License.  Therefore, by
185
+modifying or distributing the Program (or any work based on the
186
+Program), you indicate your acceptance of this License to do so, and
187
+all its terms and conditions for copying, distributing or modifying
188
+the Program or works based on it.
189
+
190
+  6. Each time you redistribute the Program (or any work based on the
191
+Program), the recipient automatically receives a license from the
192
+original licensor to copy, distribute or modify the Program subject to
193
+these terms and conditions.  You may not impose any further
194
+restrictions on the recipients' exercise of the rights granted herein.
195
+You are not responsible for enforcing compliance by third parties to
196
+this License.
197
+
198
+  7. If, as a consequence of a court judgment or allegation of patent
199
+infringement or for any other reason (not limited to patent issues),
200
+conditions are imposed on you (whether by court order, agreement or
201
+otherwise) that contradict the conditions of this License, they do not
202
+excuse you from the conditions of this License.  If you cannot
203
+distribute so as to satisfy simultaneously your obligations under this
204
+License and any other pertinent obligations, then as a consequence you
205
+may not distribute the Program at all.  For example, if a patent
206
+license would not permit royalty-free redistribution of the Program by
207
+all those who receive copies directly or indirectly through you, then
208
+the only way you could satisfy both it and this License would be to
209
+refrain entirely from distribution of the Program.
210
+
211
+If any portion of this section is held invalid or unenforceable under
212
+any particular circumstance, the balance of the section is intended to
213
+apply and the section as a whole is intended to apply in other
214
+circumstances.
215
+
216
+It is not the purpose of this section to induce you to infringe any
217
+patents or other property right claims or to contest validity of any
218
+such claims; this section has the sole purpose of protecting the
219
+integrity of the free software distribution system, which is
220
+implemented by public license practices.  Many people have made
221
+generous contributions to the wide range of software distributed
222
+through that system in reliance on consistent application of that
223
+system; it is up to the author/donor to decide if he or she is willing
224
+to distribute software through any other system and a licensee cannot
225
+impose that choice.
226
+
227
+This section is intended to make thoroughly clear what is believed to
228
+be a consequence of the rest of this License.
229
+
230
+  8. If the distribution and/or use of the Program is restricted in
231
+certain countries either by patents or by copyrighted interfaces, the
232
+original copyright holder who places the Program under this License
233
+may add an explicit geographical distribution limitation excluding
234
+those countries, so that distribution is permitted only in or among
235
+countries not thus excluded.  In such case, this License incorporates
236
+the limitation as if written in the body of this License.
237
+
238
+  9. The Free Software Foundation may publish revised and/or new versions
239
+of the General Public License from time to time.  Such new versions will
240
+be similar in spirit to the present version, but may differ in detail to
241
+address new problems or concerns.
242
+
243
+Each version is given a distinguishing version number.  If the Program
244
+specifies a version number of this License which applies to it and "any
245
+later version", you have the option of following the terms and conditions
246
+either of that version or of any later version published by the Free
247
+Software Foundation.  If the Program does not specify a version number of
248
+this License, you may choose any version ever published by the Free Software
249
+Foundation.
250
+
251
+  10. If you wish to incorporate parts of the Program into other free
252
+programs whose distribution conditions are different, write to the author
253
+to ask for permission.  For software which is copyrighted by the Free
254
+Software Foundation, write to the Free Software Foundation; we sometimes
255
+make exceptions for this.  Our decision will be guided by the two goals
256
+of preserving the free status of all derivatives of our free software and
257
+of promoting the sharing and reuse of software generally.
258
+
259
+			    NO WARRANTY
260
+
261
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
262
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
263
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
264
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
265
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
266
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
267
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
268
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
269
+REPAIR OR CORRECTION.
270
+
271
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
272
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
273
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
274
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
275
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
276
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
277
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
278
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
279
+POSSIBILITY OF SUCH DAMAGES.
280
+
281
+		     END OF TERMS AND CONDITIONS
282
+
283
+	    How to Apply These Terms to Your New Programs
284
+
285
+  If you develop a new program, and you want it to be of the greatest
286
+possible use to the public, the best way to achieve this is to make it
287
+free software which everyone can redistribute and change under these terms.
288
+
289
+  To do so, attach the following notices to the program.  It is safest
290
+to attach them to the start of each source file to most effectively
291
+convey the exclusion of warranty; and each file should have at least
292
+the "copyright" line and a pointer to where the full notice is found.
293
+
294
+    <one line to give the program's name and a brief idea of what it does.>
295
+    Copyright (C) 19yy  <name of author>
296
+
297
+    This program is free software; you can redistribute it and/or modify
298
+    it under the terms of the GNU General Public License as published by
299
+    the Free Software Foundation; either version 2 of the License, or
300
+    (at your option) any later version.
301
+
302
+    This program is distributed in the hope that it will be useful,
303
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
304
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
305
+    GNU General Public License for more details.
306
+
307
+    You should have received a copy of the GNU General Public License
308
+    along with this program; if not, write to the Free Software
309
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02110-1301  USA
310
+
311
+
312
+Also add information on how to contact you by electronic and paper mail.
313
+
314
+If the program is interactive, make it output a short notice like this
315
+when it starts in an interactive mode:
316
+
317
+    Gnomovision version 69, Copyright (C) 19yy name of author
318
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
319
+    This is free software, and you are welcome to redistribute it
320
+    under certain conditions; type `show c' for details.
321
+
322
+The hypothetical commands `show w' and `show c' should show the appropriate
323
+parts of the General Public License.  Of course, the commands you use may
324
+be called something other than `show w' and `show c'; they could even be
325
+mouse-clicks or menu items--whatever suits your program.
326
+
327
+You should also get your employer (if you work as a programmer) or your
328
+school, if any, to sign a "copyright disclaimer" for the program, if
329
+necessary.  Here is a sample; alter the names:
330
+
331
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
332
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
333
+
334
+  <signature of Ty Coon>, 1 April 1989
335
+  Ty Coon, President of Vice
336
+
337
+This General Public License does not permit incorporating your program into
338
+proprietary programs.  If your program is a subroutine library, you may
339
+consider it more useful to permit linking proprietary applications with the
340
+library.  If this is what you want to do, use the GNU Library General
341
+Public License instead of this License.

+ 183
- 0
README View File

@@ -0,0 +1,183 @@
1
+abakus, by Michael Pyne <michael.pyne@kdemail.net>
2
+Version: 0.91
3
+
4
+This is my attempt at creating a light-calculator based on Roberto Alsina's
5
+initial usability suggestions, and based on the ideas of a few other KDE
6
+hackers.
7
+
8
+This software is distributed under the terms of the GNU GPL v2.
9
+
10
+Synopsis:
11
+ $ tar xvjf abakus-0.91.tar.bz2
12
+ $ cd abakus-0.91
13
+ $ ./configure && make && make install
14
+ $ abakus
15
+
16
+Type away, and press Enter to see the result.
17
+
18
+Changes since 0.90:
19
+* Add ability to remove all functions and variables to the context menus of
20
+  their respective list boxes.
21
+* Convert out-of-range numbers to NaN.
22
+* Accept "," as a decimal separator for the benefit of European users.
23
+* Use correct decimal separator (per KLocale settings) in output.
24
+* For long results, show the beginning instead of the end of the result,
25
+  since the beginning is the most significant part of the result.
26
+
27
+Changes since 0.85:
28
+* You now have the option of using the GNU Multiple Precision library for
29
+  high-precision mathematics.  It requires the MPFR library to also be
30
+  installed (normally comes with GNU MP 4.x).  It is used automatically if
31
+  detected.
32
+* Jes Hall has contributed DocBook documentation to make Abakus integrate into
33
+  KDE even more tightly.  Thanks, Jes!
34
+* User defined functions can now be defined over.
35
+* Error handling with deriv() function improved.
36
+* Ariya Hidayat's name was misspelled everywhere in Abakus.  Sorry, Ariya. :(
37
+* Speaking of Ariya, Abakus now uses the impressive user interface code from
38
+  his SpeedCrunch calculator (http://speedcrunch.berlios.de/).  This includes
39
+  the Calc-as-you-Type tooltip, the function and variable dropdown, and
40
+  syntax highlighting.  It's not configurable at this point, expect that in
41
+  the next release.
42
+* You can use the F6 key to select the expression editor if you're a big fan
43
+  of the keyboard.
44
+* Raising negative numbers to integral powers should work with the internal
45
+  high-precision library now.
46
+* You can no longer deselect the current precision menu item.
47
+* Fix crash bug when a user-defined function refers to another user-defined
48
+  function, and then you remove or edit the function it referred to.
49
+* Add exact numerical derivatives for all functions supported.
50
+* Added the asinh, acosh, and atanh functions.
51
+* Fixed bug with loading of prior compact mode status.
52
+* Fixed bug where result text had wrong precision when you changed the
53
+  precision and tried drag-and-drop.
54
+* Drag-and-drop improvements.
55
+* Fixed bug where Custom Precision menu entry was checked even if you canceled
56
+  the dialog.
57
+* Made hyperbolic functions consistently ignore trigonometric mode.  (Both
58
+  Degrees and Radians make no sense for hyperbolic trig).
59
+* Whew! :)
60
+
61
+v0.85 adds a lot:
62
+* Improvements to the configure script.  Since I didn't end up using libCLN it
63
+  was mostly for naught, but the changes will be useful for the future.
64
+* abakus now uses the high-precision math routines from Ariya Hidayat's
65
+  SpeedCrunch program.  Thanks, Ariya!
66
+* High precision arithmetic can have between 0 and 75 digits of precision.
67
+* Support for approximate derivatives.  For most functions the derivatives will
68
+  be numerically accurate.  For those functions where I didn't feel like typing
69
+  in the exact form of the derivative an approximation is used instead.
70
+* Implicit multiplication has been added to the parser.  That means you can
71
+  type stuff like "3 sin pi" without having to manually add the * in between
72
+  3 and sin.  This also works with numbers and variables, and numbers and
73
+  parenthesized expressions.
74
+* GUI changes.  The main result view now uses KListView, so it gains tooltip
75
+  support for long answers for free, along with a bevy of other improvements.
76
+* You can right-click on an answer and copy it to the clipboard.
77
+* Corrected information in the about box.
78
+* Restarting abakus with compact mode enabled should is much improved.
79
+
80
+v0.80.2 fixed an issue with the configure script for people who don't have
81
+exactly the same version of Python I do, and forcibly prevents flex/bison
82
+errors.
83
+
84
+v0.80.1 fixed an issue with the configure script for people who don't already
85
+have scons installed.
86
+
87
+Major changes since 0.76:
88
+* There is no more C code to interface between the parser and program.
89
+* RPN mode is improved.  Now the stack is retained between calls, and there
90
+  are a few commands only in RPN mode:
91
+    1. pop   - Return the top of the stack.
92
+    2. clear - Clear the stack.
93
+* bksys is used instead of the custom Makefiles.
94
+* Lots of code cleanups, including license headers.
95
+* The nifty drag-and-drop image looks more rectangular, and is used with the
96
+  two listviews on the right as well.
97
+* Improved error checking, with messages that should hopefully be more
98
+  descriptive.
99
+
100
+Major changes since 0.75:
101
+* Reorder internal macro so that functions are declared *before* they're
102
+  referenced, which helps build the program on systems with math.h files that
103
+  don't export the long double version of their math functions.
104
+* Hitting a number or letter key right after evaluating an expression in RPN
105
+  mode automatically prepends the 'ans' variable, which was a feature of the
106
+  Normal mode.
107
+
108
+Major changes since 0.70:
109
+* Build system switched (somehow) to using qmake.  The parser and lexer are
110
+  still included, so bison and flex are still not required.  Hopefully this
111
+  will improve the ease of building.  Of course, this means no more colored
112
+  make output.
113
+* Changed most of the keyboard shortcuts to use Shift + Alt + foo instead of
114
+  Alt + foo since that was interfering with the menu bar.
115
+* RPN mode!!  If you enable RPN mode, then your expressions will be evaluated
116
+  using the Reverse Polish Notation popular with users of HP calculators.  Note
117
+  that although you can use values and functions while in RPN mode, you cannot
118
+  set or remove them from the expression editor like you can in normal mode.
119
+* abakus will display a small token starting with a dollar sign ($) in italics
120
+  next to results.  You can use these tokens to quickly reference a result in
121
+  your expression.  The most recent result is always $0, with the number
122
+  increasing from most recent to least recent result.  For example, typing
123
+  2 <Enter> 3 <Enter> $0 ^ $1 <Enter> would give a result of 9.
124
+* You can right click on functions and values in the list views to remove them
125
+  from the GUI.
126
+* Changed the result items to use word wrapping when needed to fit all the
127
+  text.
128
+* Very small DCOP interface.
129
+* More code cleanup.
130
+* Added a .desktop file.
131
+* Test client removed again.
132
+* Double-clicking on an error message (or OK message) no longer inserts them
133
+  into the edit box.
134
+
135
+Major changes since 0.61:
136
+* User defined Functions.
137
+* Save state of program between runs.
138
+* Miscellaneous fun stuff.
139
+
140
+Currently implemented features:
141
+* Parser built using flex and bison.  The generated files are included so it
142
+  should compile fine for you.
143
+* Fully C++.  The parser and lexer code require C++ to compile.
144
+* Supports several built-in functions:
145
+   - sin, cos, tan, sinh, cosh, tanh, asin, acos, atan in either radian or
146
+         degree mode.
147
+     abs, exp (e raised to the given power), ln, log (base 10),
148
+     sqrt, ceil, floor
149
+* Supported operators: +, -, *, /, ^ (or **).
150
+* Includes a window showing the values and user-defined functions you have.
151
+* Predefined constants: pi, and e (Euler' constant).
152
+* You can assign to variables by using an expression of the form:
153
+  identifier = expression.  You can then reuse these variables later.
154
+* You can create user-defined functions of one variable using the syntax
155
+  set foo(var) = <expr>, where <expr> calculates the value in terms of var.
156
+* You can delete user-defined variables by doing: remove var
157
+* You can delete user-defined functions by doing: remove foo().  Notice that
158
+  the variable is NOT included in that expression.
159
+* Functions and variables are saved on exit, and then loaded when abakus is
160
+  started again.
161
+* The ans variable contains the result of the last computation.
162
+* Pressing +, -, *, or / immediately after your last computation automatically
163
+  inserts ans for you, saving you typing.
164
+* A compact mode for the program.
165
+* Operator precedence should be correct, including the right association of
166
+  the power operator.  So, 2 ^ 3 ^ 2 == 512, just as it does when you write
167
+  it out.  You can use parentheses to force precedence.
168
+* Parentheses are not required around functions.  So, sin 3 is a valid
169
+  expression.  Note that sin 3 + cos 4 translates internally as (sin 3) + 
170
+  (cos 4), not as sin (3 + cos (4)).
171
+* I took some pains to try to make things like 3 + -2 work right.
172
+* inf and nan are accepted as numeric input for completeness.
173
+* abakus will automatically add ) characters to the end of the expression as
174
+  needed to balance your expression.  This means that expressions like
175
+  sin (cos (2 + 3 will evaluate with no error.
176
+* A rudimentary RPN mode is included.  Most everything works, except for
177
+  derivatives and creating functions or new variables.
178
+
179
+Bugs:
180
+* More functions would be nice.
181
+* The lexer assumes that the decimal marker is a period. (.)  I'm not exactly
182
+  sure how to cleanly solve this problem with flex. :-(
183
+* Documentation could be better.

+ 36
- 0
SConstruct View File

@@ -0,0 +1,36 @@
1
+#! /usr/bin/env python
2
+
3
+###################################################################
4
+# LOAD THE ENVIRONMENT AND SET UP THE TOOLS
5
+###################################################################
6
+
7
+## Load the builders in config
8
+tools    = [ 'default', 'help', 'generic', 'kde', 'abakus' ]
9
+toolpath = [ './', './bksys' ]
10
+
11
+# Required as part of SCons
12
+env = Environment(tools = tools, toolpath = toolpath)
13
+
14
+# Pull in some default settings.
15
+env.KDEuse("environ rpath nohelp")
16
+#env.KDEuse("environ rpath lang_qt thread nohelp")
17
+
18
+# If we're asking for help just go ahead and exit now.
19
+if env['HELP']:
20
+    print env.helpText()
21
+    Exit()
22
+
23
+if env['flex'] and env['bison']:
24
+    env['PARSER_INCLUDED'] = True
25
+
26
+# Export the environment so that SConscript files in subdirs can access it.
27
+Export('env')
28
+
29
+###################################################################
30
+# SCRIPTS FOR BUILDING THE TARGETS
31
+###################################################################
32
+
33
+env.subdirs('src')
34
+
35
+env.docfolder('doc/en', 'en', 'abakus/')
36
+env.SConscript('doc/en/SConscript')

+ 178
- 0
bksys/abakus.py View File

@@ -0,0 +1,178 @@
1
+#!/usr/bin/env python
2
+
3
+"""
4
+Run scons -h to display the associated help, or look below ..
5
+"""
6
+
7
+BOLD   ="\033[1m"
8
+RED    ="\033[91m"
9
+GREEN  ="\033[92m"
10
+YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds
11
+CYAN   ="\033[96m"
12
+NORMAL ="\033[0m"
13
+
14
+def exists(env):
15
+    return true
16
+
17
+def printColorCoded(msg):
18
+    msg = msg.replace(']', NORMAL)
19
+    msg = msg.replace('b[', BOLD)
20
+    msg = msg.replace('g[', GREEN)
21
+    msg = msg.replace('r[', RED)
22
+    msg = msg.replace('c[', CYAN)
23
+    msg = msg.replace('y[', YELLOW)
24
+
25
+    print msg
26
+
27
+def generate(env):
28
+    import SCons.Util, os
29
+
30
+    env.addHelpText("""b[hi]
31
+b[*** abakus options ***
32
+----------------------]
33
+b[* bison=(no|yes): Enable parser support.  Only needed for developers.
34
+b[* flex=(no|yes): Enable lexer support.  Only needed for developers.
35
+b[* mpfr=(no|yes|check): Enable the MPFR library, which is faster and more
36
+                         precise than abakus's high-precision code.
37
+
38
+ie: b[scons configure]
39
+""")
40
+
41
+    if env['HELP']:
42
+        # Don't even bother.
43
+        return env
44
+
45
+    from SCons.Options import Options, PackageOption, EnumOption
46
+    import os
47
+
48
+    def CheckFlags(context):
49
+        context.Message('Checking if ld supports --as-needed... ')
50
+        lastLINKFLAGS = context.env['LINKFLAGS']
51
+        context.env.Append(LINKFLAGS = '-Wl,--as-needed')
52
+
53
+        ret = context.TryLink("""
54
+#include <iostream>
55
+using namespace std;
56
+int main()
57
+{
58
+    cout << "Test" << endl;
59
+}
60
+""", ".cpp")
61
+        if not ret:
62
+            context.env.Replace(LINKFLAGS = lastLINKFLAGS)
63
+        context.Result(ret)
64
+        return ret
65
+
66
+    def CheckPath(context, prog, versionFlag = ''):
67
+        if context.env[prog] == 'yes':
68
+            context.env[prog] = prog
69
+
70
+        context.Message('Checking for %s... ' % prog)
71
+
72
+        ret = True
73
+
74
+        # If absolute path, just try this one.
75
+        if prog[0] == '/':
76
+            ret = context.TryAction('%s %s' % (context.env[prog], versionFlag))[0]
77
+            if ret:
78
+                context.Result(ret)
79
+                return True
80
+            
81
+        path = context.env.WhereIs(prog)
82
+        if ret and path != None:
83
+            context.env[prog] = path
84
+            context.Result(1)
85
+        else:
86
+            context.env[prog] = False
87
+            context.Result(0)
88
+        
89
+            print """
90
+The $foo program was not found!  You asked to use it so we will stop here. It
91
+is not required, you may use $foo=no on the command line to go without it.""".replace('$foo', prog)
92
+
93
+            Exit(1)
94
+
95
+            return False
96
+            
97
+        context.Result(1)
98
+        return True
99
+
100
+    cachefile = env['CACHEDIR'] + '/abakus.cache.py'
101
+
102
+    fixup = lambda x: "%s installed here (yes = search)" % x
103
+
104
+    opts = None
105
+    if env.doConfigure():
106
+        opts = Options(None, env['ARGS'])
107
+    else:
108
+        opts = Options(cachefile, env['ARGS'])
109
+
110
+    opts.AddOptions(
111
+        PackageOption('bison', fixup('use the Bison parser generator'), 'yes'),
112
+        PackageOption('flex', fixup('use the Flex scanner generator'), 'yes'),
113
+        EnumOption ('mpfr', 'use the MPFR high-precision library', 'check',
114
+                    allowed_values=('yes', 'no', 'check'), map={}, ignorecase=1),
115
+        ('ABAKUS_CONFIGURED', '', 0),
116
+        ('HAVE_ASNEEDED', '', 0)
117
+    )
118
+
119
+    # We must manually pass the ARGS in.
120
+    opts.Update(env, env['ARGS'])
121
+
122
+    if env.doConfigure() or not env['ABAKUS_CONFIGURED']:
123
+        # Configure stuff
124
+        conf = env.Configure(custom_tests = {'CheckPath': CheckPath, 'CheckFlags' : CheckFlags})
125
+
126
+        if env['bison'] and env['bison'] != 'no':
127
+            conf.CheckPath('bison', '-V')
128
+        if env['flex'] and env['flex'] != 'no':
129
+            conf.CheckPath('flex', '-V')
130
+        if env['mpfr'] != 'no':
131
+            oldLibs = conf.env.get('LIBS', '')
132
+            conf.env.AppendUnique(LIBS = 'gmp')
133
+
134
+            if conf.CheckLibWithHeader('mpfr', 'mpfr.h', 'c++', '''
135
+mpfr_t a;
136
+mpfr_ptr ptr;
137
+__mpfr_struct debug;
138
+
139
+mpfr_init(a);
140
+''', autoadd = True):
141
+                env['mpfr'] = 'yes'
142
+            else:
143
+                conf.env.Replace(LIBS = oldLibs)
144
+
145
+                if env['mpfr'] == 'yes':
146
+                    print "Unable to find requested library mpfr!"
147
+                    env.Exit(1)
148
+                else:
149
+                    env['mpfr'] = 'no'
150
+
151
+        env['HAVE_ASNEEDED'] = 0
152
+        if conf.CheckFlags():
153
+            env['HAVE_ASNEEDED'] = 1
154
+
155
+        env['ABAKUS_CONFIGURED'] = 1
156
+        env = conf.Finish()
157
+
158
+        try:
159
+            f = open("config.h", "w+")
160
+            f.write("""/* config.h -- Automatically generated by abakus.py
161
+ * Any changes you make to this file will be overwritten!
162
+ */
163
+
164
+""")
165
+            f.write("/* HAVE_MPFR -- Defined if the MPFR library is being used. */\n")
166
+            if env['mpfr'] == 'yes':
167
+                f.write ("#define HAVE_MPFR 1\n")
168
+            else:
169
+                f.write ("/* #undef HAVE_MPFR */\n")
170
+
171
+            f.close()
172
+
173
+        except IOError:
174
+            print "Unable to write config.h!"
175
+
176
+        opts.Save(cachefile, env)
177
+
178
+# vim: set et ts=8 sw=4:

+ 498
- 0
bksys/generic.py View File

@@ -0,0 +1,498 @@
1
+## Thomas Nagy, 2005
2
+
3
+"""
4
+Detect and store the most common options
5
+* kdecxxflags  : debug=1 (-g) or debug=full (-g3, slower)
6
+  else use the user CXXFLAGS if any, - or -O2 by default
7
+* prefix : the installation path
8
+* extraincludes : a list of paths separated by ':'
9
+ie: scons configure debug=full prefix=/usr/local extraincludes=/tmp/include:/usr/local
10
+"""
11
+
12
+BOLD   ="\033[1m"
13
+RED    ="\033[91m"
14
+GREEN  ="\033[92m"
15
+YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds
16
+CYAN   ="\033[96m"
17
+NORMAL ="\033[0m"
18
+
19
+import os, re, types, sys, string, shutil, stat
20
+
21
+import SCons.Defaults
22
+import SCons.Tool
23
+import SCons.Util
24
+from SCons.Script.SConscript import SConsEnvironment
25
+from SCons.Options import Options, PathOption
26
+
27
+class genobj:
28
+	def __init__(self, val, env):
29
+		if not val in "program shlib kioslave staticlib".split():
30
+			print "unknown genobj given: "+val
31
+			env.Exit(1)
32
+
33
+		self.type = val
34
+		self.orenv = env
35
+		self.env   = None
36
+		self.executed = 0
37
+
38
+		self.target=''
39
+		self.src=None
40
+
41
+		self.cxxflags=''
42
+		self.cflags=''
43
+		self.includes=''
44
+
45
+		self.linkflags=''
46
+		self.libpaths=''
47
+		self.libs=''
48
+
49
+		# vars used by shlibs
50
+		self.vnum=''
51
+		self.libprefix=''
52
+
53
+		# a directory where to install the targets (optional)
54
+		self.instdir=''
55
+		# ignore the DESTDIR (optional)
56
+		self.nodestdir=''
57
+
58
+		# change the working directory before reading the targets
59
+		self.chdir=''
60
+
61
+		# these members are private
62
+		self.chdir_lock=None
63
+		self.old_os_dir=''
64
+		self.old_fs_dir=''
65
+		self.p_local_shlibs=[]
66
+		self.p_local_staticlibs=[]
67
+		self.p_global_shlibs=[]
68
+
69
+		#if not env.has_key('USE_THE_FORCE_LUKE'): env['USE_THE_FORCE_LUKE']=[self]
70
+		#else: env['USE_THE_FORCE_LUKE'].append(self)
71
+
72
+	def lockchdir(self):
73
+		if not self.chdir: return
74
+		self.chdir_lock=1
75
+		SConfFS=SCons.Node.FS.default_fs
76
+		self.old_fs_dir=SConfFS.getcwd()
77
+		self.old_os_dir=os.getcwd()
78
+		#os.chdir(old_os_dir+'/'+self.chdir)
79
+		SConfFS.chdir( SConfFS.Dir('#/'+self.chdir), change_os_dir=1)
80
+
81
+	def unlockchdir(self):
82
+		if not self.chdir: return
83
+		if self.chdir_lock:
84
+			#os.chdir(self.old_os_dir)
85
+			SCons.Node.FS.default_fs.chdir(self.old_fs_dir, change_os_dir=0)
86
+			self.chdir_lock=None
87
+
88
+	def execute(self):
89
+		if self.orenv.has_key('DUMPCONFIG'):
90
+			print self.xml()
91
+			return
92
+
93
+		self.lockchdir()
94
+
95
+		self.env = self.orenv.Copy()
96
+
97
+		if not self.src or len(self.src) == 0:
98
+			print RED+"no source file given to object - self.src"+NORMAL
99
+			self.env.Exit(1)
100
+		if not self.env.has_key('nosmart_includes'): self.env.AppendUnique(CPPPATH=['./'])
101
+		if self.type == "kioslave": self.libprefix=''
102
+
103
+		if len(self.includes)>0: self.env.AppendUnique(CPPPATH=self.env.make_list(self.includes))
104
+		if len(self.cxxflags)>0: self.env.AppendUnique(CXXFLAGS=self.env.make_list(self.cxxflags))
105
+		if len(self.cflags)>0: self.env.AppendUnique(CCFLAGS=self.env.make_list(self.cflags))
106
+
107
+		llist=self.env.make_list(self.libs)
108
+		lext='.so .la'.split()
109
+		sext='.a'.split()
110
+		for l in llist:
111
+			sal=SCons.Util.splitext(l)
112
+			if len(sal)>1:
113
+				if sal[1] in lext: self.p_local_shlibs.append(sal[0]+'.so')
114
+				elif sal[1] in sext: self.p_local_staticlibs.append(sal[0]+'.a')
115
+				else: self.p_global_shlibs.append(l)
116
+
117
+		if len(self.p_global_shlibs)>0: self.env.AppendUnique(LIBS=self.p_global_shlibs)
118
+		if len(self.libpaths)>0:   self.env.PrependUnique(LIBPATH=self.env.make_list(self.libpaths))
119
+		if len(self.linkflags)>0:  self.env.PrependUnique(LINKFLAGS=self.env.make_list(self.linkflags))
120
+
121
+		# the target to return
122
+		ret=None
123
+		if self.type=='shlib' or self.type=='kioslave':
124
+			ret=self.env.bksys_shlib(self.target, self.src, self.instdir, 
125
+				self.libprefix, self.vnum, nodestdir=self.nodestdir)
126
+		elif self.type=='program':
127
+			ret=self.env.Program(self.target, self.src)
128
+			if not self.env.has_key('NOAUTOINSTALL'):
129
+				self.env.bksys_install(self.instdir, ret, nodestdir=self.nodestdir)
130
+		elif self.type=='staticlib':
131
+			ret=self.env.StaticLibrary(self.target, self.src)
132
+
133
+		# we link the program against a shared library made locally, add the dependency
134
+		if len(self.p_local_shlibs)>0:
135
+			self.env.link_local_shlib(self.p_local_shlibs)
136
+			if ret: self.env.Depends( ret, self.p_local_shlibs )
137
+		if len(self.p_local_staticlibs)>0:
138
+			self.env.link_local_staticlib(self.p_local_staticlibs)
139
+			if ret: self.env.Depends( ret, self.p_local_staticlibs )
140
+
141
+		self.unlockchdir()
142
+
143
+## Copy function that honors symlinks
144
+def copy_bksys(dest, source, env):
145
+        if os.path.islink(source):
146
+		#print "symlinking "+source+" "+dest
147
+		if os.path.islink(dest):
148
+			os.unlink(dest)
149
+		os.symlink(os.readlink(source), dest)
150
+	else:
151
+		shutil.copy2(source, dest)
152
+		st=os.stat(source)
153
+		os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
154
+	return 0
155
+
156
+## Return a list of things
157
+def make_list(env, s):
158
+	if type(s) is types.ListType:
159
+		return s
160
+	else:
161
+		return s.split()
162
+
163
+def exists(env):
164
+	return true
165
+
166
+def generate(env):
167
+	## Bksys requires scons 0.96
168
+	env.EnsureSConsVersion(0, 96)
169
+
170
+	SConsEnvironment.make_list = make_list
171
+	def doConfigure(env):
172
+		return not env['HELP'] and (env['_CONFIGURE'] or not env.has_key('ISCONFIGURED'))
173
+
174
+	SConsEnvironment.doConfigure = doConfigure
175
+	env['HELP']=0
176
+	if '--help' in sys.argv or '-h' in sys.argv or 'help' in sys.argv:
177
+		env['HELP']=1
178
+	
179
+	env.addHelpText("""
180
+b[*** Generic options ***
181
+-----------------------]
182
+b[* debug  ]: debug=1 (-g) or debug=full (-g3, slower), otherwise use
183
+              environment CXXFLAGS, or -O2 by default.
184
+b[* prefix ]: the installation path
185
+b[* extraincludes ]: a list of paths separated by ':'
186
+
187
+ie: b[scons configure debug=full prefix=/usr/local extraincludes=/tmp/include:/usr/local]
188
+""")
189
+	
190
+	## Global cache directory
191
+	# Put all project files in it so a rm -rf cache will clean up the config
192
+	if not env.has_key('CACHEDIR'):
193
+		env['CACHEDIR'] = os.getcwd()+'/cache/'
194
+	if not os.path.isdir(env['CACHEDIR']):
195
+		os.mkdir(env['CACHEDIR'])
196
+	
197
+	## SCons cache directory
198
+	# This avoids recompiling the same files over and over again: 
199
+	# very handy when working with cvs
200
+	if os.getuid() != 0:
201
+		env.CacheDir(os.getcwd()+'/cache/objects')
202
+
203
+	#  Avoid spreading .sconsign files everywhere - keep this line
204
+	env.SConsignFile(env['CACHEDIR']+'/scons_signatures')
205
+	
206
+	def makeHashTable(args):
207
+		table = { }
208
+		for arg in args:
209
+			if len(arg) > 1:
210
+				lst=arg.split('=')
211
+				if len(lst) < 2:
212
+					continue
213
+				key=lst[0]
214
+				value=lst[1]
215
+				if len(key) > 0 and len(value) >0:
216
+					table[key] = value
217
+ 		return table
218
+
219
+	env['ARGS']=makeHashTable(sys.argv)
220
+
221
+	## Special trick for installing rpms ...
222
+	env['DESTDIR']=''
223
+	if 'install' in sys.argv:
224
+		dd=''
225
+		if os.environ.has_key('DESTDIR'):
226
+			dd=os.environ['DESTDIR']
227
+		if not dd:
228
+			if env['ARGS']: dd=env['ARGS']['DESTDIR']
229
+		if dd:
230
+			env['DESTDIR']=dd+'/'
231
+			print CYAN+'** Enabling DESTDIR for the project ** ' + NORMAL + env['DESTDIR']
232
+
233
+	## install symlinks for shared libraries properly
234
+	env['INSTALL'] = copy_bksys
235
+
236
+	## Use the same extension .o for all object files
237
+	env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
238
+
239
+	## load the options
240
+	cachefile=env['CACHEDIR']+'generic.cache.py'
241
+	opts = Options(cachefile)
242
+	opts.AddOptions(
243
+		( 'GENCCFLAGS', 'C flags' ),
244
+		( 'GENCXXFLAGS', 'debug level for the project : full or just anything' ),
245
+		( 'GENLINKFLAGS', 'additional link flags' ),
246
+		( 'PREFIX', 'prefix for installation' ),
247
+		( 'EXTRAINCLUDES', 'extra include paths for the project' ),
248
+		( 'ISCONFIGURED', 'is the project configured' ),
249
+	)
250
+	opts.Update(env)
251
+	
252
+	# Use this to avoid an error message 'how to make target configure ?'
253
+	env.Alias('configure', None)
254
+
255
+	# Check if the following command line arguments have been given
256
+	# and set a flag in the environment to show whether or not it was
257
+	# given.
258
+	if 'install' in sys.argv:
259
+		env['_INSTALL']=1
260
+	else:
261
+		env['_INSTALL']=0
262
+	if 'configure' in sys.argv:
263
+		env['_CONFIGURE']=1
264
+	else:
265
+		env['_CONFIGURE']=0
266
+
267
+	# Configure the environment if needed
268
+	if doConfigure(env):
269
+		# be paranoid, unset existing variables
270
+		for var in "GENCXXFLAGS GENCCFLAGS GENLINKFLAGS PREFIX EXTRAINCLUDES ISCONFIGURED EXTRAINCLUDES".split():
271
+			if env.has_key(var): env.__delitem__(var)
272
+
273
+		if env['ARGS'].get('debug', None):
274
+			debuglevel = env['ARGS'].get('debug', None)
275
+			print CYAN+'** Enabling debug for the project **' + NORMAL
276
+			if (debuglevel == "full"):
277
+				env['GENCXXFLAGS'] = ['-DDEBUG', '-g3', '-Wall']
278
+			else:
279
+				env['GENCXXFLAGS'] = ['-DDEBUG', '-g', '-Wall']
280
+		else:
281
+			if os.environ.has_key('CXXFLAGS'):
282
+				# user-defined flags (gentooers will be elighted)
283
+				env['GENCXXFLAGS'] = SCons.Util.CLVar( os.environ['CXXFLAGS'] )
284
+				env.Append( GENCXXFLAGS = ['-DNDEBUG', '-DNO_DEBUG'] )
285
+			else:
286
+				env.Append(GENCXXFLAGS = ['-O2', '-DNDEBUG', '-DNO_DEBUG'])
287
+
288
+		if os.environ.has_key('CFLAGS'):
289
+			env['GENCCFLAGS'] = SCons.Util.CLVar( os.environ['CFLAGS'] )
290
+
291
+		## FreeBSD settings (contributed by will at freebsd dot org)
292
+		if os.uname()[0] == "FreeBSD":
293
+			if os.environ.has_key('PTHREAD_LIBS'):
294
+				env.AppendUnique( GENLINKFLAGS = SCons.Util.CLVar( os.environ['PTHREAD_LIBS'] ) )
295
+		        else:
296
+				syspf = os.popen('/sbin/sysctl kern.osreldate')
297
+				osreldate = int(syspf.read().split()[1])
298
+				syspf.close()
299
+				if osreldate < 500016:
300
+					env.AppendUnique( GENLINKFLAGS = ['-pthread'])
301
+					env.AppendUnique( GENCXXFLAGS = ['-D_THREAD_SAFE'])
302
+				elif osreldate < 502102:
303
+					env.AppendUnique( GENLINKFLAGS = ['-lc_r'])
304
+					env.AppendUnique( GENCXXFLAGS = ['-D_THREAD_SAFE'])
305
+				else:
306
+					env.AppendUnique( GENLINKFLAGS = ['-pthread'])
307
+
308
+		# User-specified prefix
309
+		if env['ARGS'].has_key('prefix'):
310
+			env['PREFIX'] = os.path.abspath( env['ARGS'].get('prefix', '') )
311
+			print (CYAN+'** installation prefix for the project set to : ' +
312
+			       env['PREFIX'] +' **'+ NORMAL)
313
+
314
+		# User-specified include paths
315
+		env['EXTRAINCLUDES'] = env['ARGS'].get('extraincludes', None)
316
+		if env['EXTRAINCLUDES']:
317
+			print (CYAN+'** extra include paths for the project set to: ' +
318
+			       env['EXTRAINCLUDES'] +' **'+ NORMAL)
319
+
320
+		env['ISCONFIGURED']=1
321
+
322
+		# And finally save the options in the cache
323
+		opts.Save(cachefile, env)
324
+
325
+	def bksys_install(lenv, subdir, files, destfile=None, nodestdir=None):
326
+		""" Install files on "scons install"
327
+		If the DESTDIR env variable has been set, (e.g. by 
328
+		"scons install DESTDIR=$CURDIR/debian) then install files to that
329
+		directory, regardless of where the configure stage showed that
330
+		files should be installed.
331
+		This feature is useful for packagers, and users of GNU stow.
332
+		
333
+		NB. The DESTDIR will be ignored if NODESTDIR is also set, although
334
+		the same effect can be acheived by not setting DESTDIR in the first
335
+		place."""
336
+
337
+		if not env['_INSTALL']:
338
+			return
339
+		basedir = env['DESTDIR']
340
+		if nodestdir or env.has_key('NODESTDIR') : basedir = "/"
341
+		install_list = None
342
+		if not destfile:
343
+			install_list = env.Install(basedir+subdir+'/', files)
344
+		else:
345
+			if subdir:
346
+				install_list = env.InstallAs(basedir+subdir+'/'+destfile, files)
347
+			else:
348
+				install_list = env.InstallAs(basedir+'/'+destfile, files)
349
+		env.Alias('install', install_list)
350
+		return install_list
351
+
352
+	def build_la_file(target, source, env):
353
+		""" Action for building libtool files.
354
+		Writes a .la file, as used by libtool."""
355
+		dest=open(target[0].path, 'w')
356
+		sname=source[0].name
357
+		dest.write("dlname='%s'\n" % sname)
358
+		if len(env['BKSYS_VNUM'])>0:
359
+			vnum=env['BKSYS_VNUM']
360
+			nums=vnum.split('.')
361
+			src=source[0].name
362
+			name = src.split('so.')[0] + 'so'
363
+			strn = src+" "+name+"."+str(nums[0])+" "+name
364
+			dest.write("library_names='%s'\n" % (strn) )
365
+		else:
366
+			dest.write("library_names='%s %s %s'\n" % (sname, sname, sname) )
367
+		dest.write("old_library=''\ndependency_libs=''\ncurrent=0\n")
368
+		dest.write("age=0\nrevision=0\ninstalled=yes\nshouldnotlink=no\n")
369
+		dest.write("dlopen=''\ndlpreopen=''\n")
370
+		dest.write("libdir='%s'" % env['BKSYS_DESTDIR'])
371
+		dest.close()
372
+		return 0
373
+
374
+	def string_la_file(target, source, env):
375
+		print "building '%s' from '%s'" % (target[0].name, source[0].name)
376
+	la_file = env.Action(build_la_file, string_la_file, ['BKSYS_VNUM', 'BKSYS_DESTDIR'])
377
+	env['BUILDERS']['LaFile'] = env.Builder(action=la_file,suffix='.la',src_suffix=env['SHLIBSUFFIX'])
378
+
379
+	## Function for building shared libraries
380
+	def bksys_shlib(lenv, target, source, libdir, libprefix='lib', vnum='', noinst=None, nodestdir=None):
381
+		""" Install a shared library.
382
+		
383
+		Installs a shared library, with or without a version number, and create a
384
+		.la file for use by libtool.
385
+		
386
+		If library version numbering is to be used, the version number
387
+		should be passed as a period-delimited version number (e.g.
388
+		vnum = '1.2.3').  This causes the library to be installed
389
+		with its full version number, and with symlinks pointing to it.
390
+		
391
+		For example, for libfoo version 1.2.3, install the file
392
+		libfoo.so.1.2.3, and create symlinks libfoo.so and
393
+		libfoo.so.1 that point to it.
394
+		"""
395
+		thisenv = lenv.Copy() # copying an existing environment is cheap
396
+		thisenv['BKSYS_DESTDIR']=libdir
397
+		thisenv['BKSYS_VNUM']=vnum
398
+		thisenv['SHLIBPREFIX']=libprefix
399
+
400
+		if len(vnum)>0:
401
+			thisenv['SHLIBSUFFIX']='.so.'+vnum
402
+			thisenv.Depends(target, thisenv.Value(vnum))
403
+
404
+		# Fix against a scons bug - shared libs and ordinal out of range(128)
405
+		if type(source) is types.ListType:
406
+			src2=[]
407
+			for i in source:
408
+				src2.append( str(i) )
409
+			source=src2
410
+
411
+		library_list = thisenv.SharedLibrary(target, source)
412
+		lafile_list  = thisenv.LaFile(target, library_list)
413
+
414
+		## Install the libraries automatically
415
+		if not thisenv.has_key('NOAUTOINSTALL') and not noinst:
416
+			thisenv.bksys_install(libdir, library_list, nodestdir=nodestdir)
417
+			thisenv.bksys_install(libdir, lafile_list, nodestdir=nodestdir)	
418
+
419
+		## Handle the versioning
420
+		if len(vnum)>0:
421
+			nums=vnum.split('.')
422
+			symlinkcom = ('cd $TARGET.dir && ' +
423
+			              'rm -f $TARGET.name && ' +
424
+			              'ln -s $SOURCE.name $TARGET.name')
425
+			tg = target+'.so.'+vnum
426
+			nm1 = target+'.so'
427
+			nm2 = target+'.so.'+nums[0]
428
+			
429
+			thisenv.Command(nm1, tg, symlinkcom)
430
+			thisenv.Command(nm2, tg, symlinkcom)
431
+
432
+			#base=env['DESTDIR']+libdir+'/'
433
+			thisenv.bksys_install(libdir, nm1, nodestdir=nodestdir)
434
+			thisenv.bksys_install(libdir, nm2, nodestdir=nodestdir)
435
+
436
+	# Declare scons scripts to process
437
+	def subdirs(lenv, folderlist):
438
+		flist=[]
439
+		if type(folderlist) is types.ListType: flist = folderlist
440
+		else: flist = folderlist.split()
441
+		for i in flist:
442
+			lenv.SConscript(i+"/SConscript")
443
+
444
+        def link_local_shlib(lenv, str):
445
+                """ Links against a shared library made in the project """
446
+                lst = lenv.make_list(str)
447
+		for file in lst:
448
+			import re
449
+			reg = re.compile("(.*)/lib(.*).(la|so)")
450
+			result = reg.match(file)
451
+			if not result:
452
+				print "Unknown la file given "+file
453
+				continue
454
+			dir  = result.group(1)
455
+			link = result.group(2)
456
+			lenv.AppendUnique(LIBS = [link])
457
+			lenv.PrependUnique(LIBPATH = [dir])
458
+
459
+        def link_local_staticlib(lenv, str):
460
+                """ Links against a shared library made in the project """
461
+                lst = lenv.make_list(str)
462
+		for file in lst:
463
+			import re
464
+			reg = re.compile("(.*)/(lib.*.a)")
465
+			result = reg.match(file)
466
+			if not result:
467
+				print "Unknown archive file given "+file
468
+				continue
469
+
470
+			f=SCons.Node.FS.default_fs.File(file)
471
+			lenv.Append(LINKFLAGS=[f.path])
472
+
473
+	#valid_targets = "program shlib kioslave staticlib".split()
474
+        SConsEnvironment.bksys_install = bksys_install
475
+	SConsEnvironment.bksys_shlib   = bksys_shlib
476
+	SConsEnvironment.subdirs       = subdirs
477
+	SConsEnvironment.link_local_shlib = link_local_shlib
478
+	SConsEnvironment.link_local_staticlib = link_local_staticlib
479
+
480
+	SConsEnvironment.genobj=genobj
481
+
482
+	if env.has_key('GENCXXFLAGS'):
483
+		env.PrependUnique( CXXFLAGS = env['GENCXXFLAGS'] )
484
+
485
+	if env.has_key('GENCCFLAGS'):
486
+		env.AppendUnique( CCFLAGS = env['GENCCFLAGS'] )
487
+
488
+	if env.has_key('GENLINKFLAGS'):
489
+		env.AppendUnique( LINKFLAGS = env['GENLINKFLAGS'] )
490
+
491
+	if env.has_key('EXTRAINCLUDES'):
492
+		if env['EXTRAINCLUDES']:
493
+			incpaths = []
494
+			for dir in str(env['EXTRAINCLUDES']).split(':'):
495
+				incpaths.append( dir )
496
+			env.Append(CPPPATH = incpaths)
497
+
498
+	env.Export('env')

+ 43
- 0
bksys/help.py View File

@@ -0,0 +1,43 @@
1
+## Thomas Nagy, 2005
2
+
3
+"""
4
+Detect and store the most common options
5
+* kdecxxflags  : debug=1 (-g) or debug=full (-g3, slower)
6
+  else use the user CXXFLAGS if any, - or -O2 by default
7
+* prefix : the installation path
8
+* extraincludes : a list of paths separated by ':'
9
+ie: scons configure debug=full prefix=/usr/local extraincludes=/tmp/include:/usr/local
10
+"""
11
+
12
+BOLD   ="\033[1m"
13
+RED    ="\033[91m"
14
+GREEN  ="\033[92m"
15
+YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds
16
+CYAN   ="\033[96m"
17
+NORMAL ="\033[0m"
18
+
19
+def exists(env):
20
+	return true
21
+
22
+def generate(env):
23
+	## Bksys requires scons 0.96
24
+	env.EnsureSConsVersion(0, 96)
25
+
26
+	env._help = ''
27
+
28
+	def addHelpText(env, text):
29
+		env._help = env._help + text
30
+
31
+	def helpText(env):
32
+		text = env._help.replace(']', NORMAL)
33
+		text = text.replace('b[', BOLD)
34
+		text = text.replace('g[', GREEN)
35
+		text = text.replace('r[', RED)
36
+		text = text.replace('y[', YELLOW)
37
+		text = text.replace('c[', CYAN)
38
+
39
+		return text
40
+
41
+	from SCons.Script.SConscript import SConsEnvironment
42
+	SConsEnvironment.addHelpText = addHelpText
43
+	SConsEnvironment.helpText = helpText

+ 820
- 0
bksys/kde.py View File

@@ -0,0 +1,820 @@
1
+# Made from scons qt.py and (heavily) modified into kde.py
2
+# Thomas Nagy, 2004, 2005 <tnagy2^8@yahoo.fr>
3
+
4
+"""
5
+Run scons -h to display the associated help, or look below ..
6
+"""
7
+
8
+BOLD   ="\033[1m"
9
+RED    ="\033[91m"
10
+GREEN  ="\033[92m"
11
+YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds
12
+CYAN   ="\033[96m"
13
+NORMAL ="\033[0m"
14
+
15
+import os, re, types
16
+from SCons.Script.SConscript import SConsEnvironment
17
+
18
+# Returns the name of the shared object (i.e. libkdeui.so.4)
19
+# referenced by a libtool archive (like libkdeui.la)
20
+def getSOfromLA(lafile):
21
+	contents = open(lafile, 'r').read()
22
+	match = re.search("^dlname='([^']*)'$", contents, re.M)
23
+	if match:
24
+		return match.group(1)
25
+	return None
26
+
27
+# A helper, needed .. everywhere
28
+def KDEuse(lenv, flags):
29
+	if lenv['HELP']: lenv.Exit(0)
30
+
31
+	_flags=lenv.make_list(flags)
32
+	if 'environ' in _flags:
33
+		## The scons developers advise against using this but it is mostly innocuous :)
34
+		lenv.AppendUnique( ENV = os.environ )
35
+	if not 'lang_qt' in _flags:
36
+		## Use this define if you are using the kde translation scheme (.po files)
37
+		lenv.Append( CPPFLAGS = '-DQT_NO_TRANSLATION' )
38
+	if 'rpath' in _flags:
39
+		## Use this to set rpath - this may cause trouble if folders are moved (chrpath)
40
+		lenv.Append( RPATH = [lenv['QTLIBPATH'], lenv['KDELIBPATH'], lenv['KDEMODULE']] )
41
+		kdelibpaths=[]
42
+		if lenv['KDELIBPATH'] == lenv['KDELIB']:
43
+			kdelibpaths = [lenv['KDELIB']]
44
+		else:
45
+			kdelibpaths = [lenv['KDELIBPATH'],  lenv['KDELIB']]
46
+		lenv.Append( RPATH = [lenv['QTLIBPATH'], lenv['KDEMODULE']]+kdelibpaths )
47
+	if 'thread' in _flags:
48
+		## Uncomment the following if you need threading support
49
+		lenv.KDEaddflags_cxx( ['-DQT_THREAD_SUPPORT', '-D_REENTRANT'] )
50
+	if 'fastmoc' in _flags:
51
+		lenv['BKSYS_FASTMOC']=1
52
+	if not 'nohelp' in _flags:
53
+		if lenv['_CONFIGURE'] or lenv['HELP']:
54
+			lenv.Exit(0)
55
+	if not 'nosmart' or not lenv.has_key('nosmart_includes'):
56
+		lenv.AppendUnique(CPPPATH=['#/'])
57
+		lst=[]
58
+		if lenv.has_key('USE_THE_FORCE_LUKE'):
59
+			lst=lenv['USE_THE_FORCE_LUKE']
60
+			lenv.__delitem__('USE_THE_FORCE_LUKE')
61
+		for v in lst:
62
+			v.execute()
63
+	else:
64
+			lenv['nosmart_includes']=1
65
+
66
+	## To use kdDebug(intvalue)<<"some trace"<<endl; you need to define -DDEBUG
67
+	## it is done in admin/generic.py automatically when you do scons configure debug=1
68
+
69
+def exists(env):
70
+	return True
71
+
72
+def detect_kde(env):
73
+	""" Detect the qt and kde environment using kde-config mostly """
74
+        def getpath(varname):
75
+                if not env.has_key('ARGS'): return None
76
+                v=env['ARGS'].get(varname, None)
77
+                if v: v=os.path.abspath(v)
78
+                return v
79
+
80
+        prefix      = getpath('prefix')
81
+        execprefix  = getpath('execprefix')
82
+        datadir     = getpath('datadir')
83
+        libdir      = getpath('libdir')
84
+        kdeincludes = getpath('kdeincludes')
85
+        kdelibs     = getpath('kdelibs')
86
+        qtincludes  = getpath('qtincludes')
87
+        qtlibs      = getpath('qtlibs')
88
+        libsuffix   = ''
89
+        if env.has_key('ARGS'): libsuffix=env['ARGS'].get('libsuffix', '')
90
+
91
+	if libdir: libdir = libdir+libsuffix
92
+
93
+	## Detect the kde libraries
94
+	print "Checking for kde-config           : ",
95
+	kde_config = os.popen("which kde-config 2>/dev/null").read().strip()
96
+	if len(kde_config):
97
+		print GREEN+"kde-config was found"+NORMAL
98
+	else:
99
+		print RED+"kde-config was NOT found in your PATH"+NORMAL
100
+		print "Make sure kde is installed properly"
101
+		print "(missing package kdebase-devel?)"
102
+		env.Exit(1)
103
+	env['KDEDIR'] = os.popen('kde-config -prefix').read().strip()
104
+
105
+	print "Checking for kde version          : ",
106
+	kde_version = os.popen("kde-config --version|grep KDE").read().strip().split()[1]
107
+	if int(kde_version[0]) != 3 or int(kde_version[2]) < 2:
108
+		print RED+kde_version
109
+		print RED+"Your kde version can be too old"+NORMAL
110
+		print RED+"Please make sure kde is at least 3.2"+NORMAL
111
+	else:
112
+		print GREEN+kde_version+NORMAL
113
+
114
+	## Detect the qt library
115
+	print "Checking for the qt library       : ",
116
+	qtdir = os.getenv("QTDIR")
117
+	if qtdir:
118
+		print GREEN+"qt is in "+qtdir+NORMAL
119
+	else:
120
+		try:
121
+			tmplibdir = os.popen('kde-config --expandvars --install lib').read().strip()
122
+			libkdeuiSO = tmplibdir+'/'+getSOfromLA(tmplibdir+'/libkdeui.la')
123
+			m = re.search('(.*)/lib/libqt.*', os.popen('ldd ' + libkdeuiSO + ' | grep libqt').read().strip().split()[2])
124
+		except:
125
+			m=None
126
+		if m:
127
+			qtdir = m.group(1)
128
+			print YELLOW+"qt was found as "+m.group(1)+NORMAL
129
+		else:
130
+			print RED+"qt was not found"+NORMAL
131
+			print RED+"Please set QTDIR first (/usr/lib/qt3?) or try scons -h for more options"+NORMAL
132
+			env.Exit(1)
133
+	env['QTDIR'] = qtdir.strip()
134
+
135
+	## Find the necessary programs uic and moc
136
+	print "Checking for uic                  : ",
137
+	uic = qtdir + "/bin/uic"
138
+	if os.path.isfile(uic):
139
+		print GREEN+"uic was found as "+uic+NORMAL
140
+	else:
141
+		uic = os.popen("which uic 2>/dev/null").read().strip()
142
+		if len(uic):
143
+			print YELLOW+"uic was found as "+uic+NORMAL
144
+		else:
145
+			uic = os.popen("which uic 2>/dev/null").read().strip()
146
+			if len(uic):
147
+				print YELLOW+"uic was found as "+uic+NORMAL
148
+			else:
149
+				print RED+"uic was not found - set QTDIR put it in your PATH ?"+NORMAL
150
+				env.Exit(1)
151
+	env['QT_UIC'] = uic
152
+
153
+	print "Checking for moc                  : ",
154
+	moc = qtdir + "/bin/moc"
155
+	if os.path.isfile(moc):
156
+		print GREEN + "moc was found as " + moc + NORMAL
157
+	else:
158
+		moc = os.popen("which moc 2>/dev/null").read().strip()
159
+		if len(moc):
160
+			print YELLOW + "moc was found as " + moc + NORMAL
161
+		elif os.path.isfile("/usr/share/qt3/bin/moc"):
162
+			moc = "/usr/share/qt3/bin/moc"
163
+			print YELLOW + "moc was found as " + moc + NORMAL
164
+		else:
165
+			print RED + "moc was not found - set QTDIR or put it in your PATH ?" + NORMAL
166
+			env.Exit(1)
167
+	env['QT_MOC'] = moc
168
+
169
+	## check for the qt and kde includes
170
+	print "Checking for the qt includes      : ",
171
+	if qtincludes and os.path.isfile(qtincludes + "/qlayout.h"):
172
+		# The user told where to look for and it looks valid
173
+		print GREEN + "ok " + qtincludes + NORMAL
174
+	else:
175
+		if os.path.isfile(qtdir + "/include/qlayout.h"):
176
+			# Automatic detection
177
+			print GREEN + "ok " + qtdir + "/include/ " + NORMAL
178
+			qtincludes = qtdir + "/include/"
179
+		elif os.path.isfile("/usr/include/qt3/qlayout.h"):
180
+			# Debian probably
181
+			print YELLOW + "the qt headers were found in /usr/include/qt3/ " + NORMAL
182
+			qtincludes = "/usr/include/qt3"
183
+		else:
184
+			print RED + "the qt headers were not found" + NORMAL
185
+			env.Exit(1)
186
+
187
+	print "Checking for the kde includes     : ",
188
+	kdeprefix = os.popen("kde-config --prefix").read().strip()
189
+	if not kdeincludes:
190
+		kdeincludes = kdeprefix+"/include/"
191
+	if os.path.isfile(kdeincludes + "/klineedit.h"):
192
+		print GREEN + "ok " + kdeincludes + NORMAL
193
+	else:
194
+		if os.path.isfile(kdeprefix+"/include/kde/klineedit.h"):
195
+			# Debian, Fedora probably
196
+			print YELLOW + "the kde headers were found in " + kdeprefix + "/include/kde/" + NORMAL
197
+			kdeincludes = kdeprefix + "/include/kde/"
198
+		else:
199
+			print RED + "The kde includes were NOT found" + NORMAL
200
+			env.Exit(1)
201
+
202
+	# kde-config options
203
+	kdec_opts = {'KDEBIN'    : 'exe',     'KDEAPPS'      : 'apps',
204
+		     'KDEDATA'   : 'data',    'KDEICONS'     : 'icon',
205
+		     'KDEMODULE' : 'module',  'KDELOCALE'    : 'locale',
206
+		     'KDEKCFG'   : 'kcfg',    'KDEDOC'       : 'html',
207
+		     'KDEMENU'   : 'apps',    'KDEXDG'       : 'xdgdata-apps',
208
+		     'KDEMIME'   : 'mime',    'KDEXDGDIR'    : 'xdgdata-dirs',
209
+		     'KDESERV'   : 'services','KDESERVTYPES' : 'servicetypes',
210
+		     'KDEINCLUDE': 'include'
211
+		     }
212
+
213
+	if prefix:
214
+		## use the user-specified prefix
215
+		if not execprefix:
216
+			execprefix = prefix
217
+		if not datadir:
218
+			datadir=prefix+"/share"
219
+		if not libdir:
220
+			libdir=execprefix+"/lib"+libsuffix
221
+
222
+		subst_vars = lambda x: x.replace('${exec_prefix}', execprefix)\
223
+			     .replace('${datadir}', datadir)\
224
+			     .replace('${libdir}', libdir)
225
+		debian_fix = lambda x: x.replace('/usr/share', '${datadir}')
226
+		env['PREFIX'] = prefix
227
+		env['KDELIB'] = libdir
228
+		for (var, option) in kdec_opts.items():
229
+			dir = os.popen('kde-config --install ' + option).read().strip()
230
+			if var == 'KDEDOC': dir = debian_fix(dir)
231
+			env[var] = subst_vars(dir)
232
+
233
+	else:
234
+		env['PREFIX'] = os.popen('kde-config --expandvars --prefix').read().strip()
235
+		env['KDELIB'] = os.popen('kde-config --expandvars --install lib').read().strip()
236
+		for (var, option) in kdec_opts.items():
237
+			dir = os.popen('kde-config --expandvars --install ' + option).read().strip()
238
+			env[var] = dir
239
+
240
+	env['QTPLUGINS']=os.popen('kde-config --expandvars --install qtplugins').read().strip()
241
+
242
+	## kde libs and includes
243
+	env['KDEINCLUDEPATH']=kdeincludes
244
+	if not kdelibs:
245
+		kdelibs=os.popen('kde-config --expandvars --install lib').read().strip()
246
+	env['KDELIBPATH']=kdelibs
247
+
248
+	## qt libs and includes
249
+	env['QTINCLUDEPATH']=qtincludes
250
+	if not qtlibs:
251
+		qtlibs=qtdir+"/lib"+libsuffix
252
+	env['QTLIBPATH']=qtlibs
253
+
254
+def generate(env):
255
+	""""Set up the qt and kde environment and builders - the moc part is difficult to understand """
256
+
257
+	# attach this function immediately
258
+	SConsEnvironment.KDEuse = KDEuse
259
+	env.addHelpText("""
260
+b[*** KDE options ***
261
+-------------------]
262
+b[* prefix     ]: base install path,         ie: /usr/local
263
+b[* execprefix ]: install path for binaries, ie: /usr/bin
264
+b[* datadir    ]: install path for the data, ie: /usr/local/share
265
+b[* libdir     ]: install path for the libs, ie: /usr/lib
266
+b[* libsuffix  ]: suffix of libraries on amd64, ie: 64, 32
267
+b[* kdeincludes]: path to the kde includes (/usr/include/kde on debian, ...)
268
+b[* qtincludes ]: path to the for qt includes (/usr/include/qt on debian, ...)
269
+b[* kdelibs    ]: path to the kde libs, for linking the programs
270
+b[* qtlibs     ]: path to the qt libs, for linking the programs
271
+
272
+ie: b[scons configure libdir=/usr/local/lib qtincludes=/usr/include/qt]
273
+""")
274
+
275
+	import SCons.Defaults
276
+	import SCons.Tool
277
+	import SCons.Util
278
+	import SCons.Node
279
+
280
+	CLVar = SCons.Util.CLVar
281
+	splitext = SCons.Util.splitext
282
+	Builder = SCons.Builder.Builder
283
+	
284
+	# Detect the environment - replaces ./configure implicitely and store the options into a cache
285
+	from SCons.Options import Options
286
+	cachefile=env['CACHEDIR']+'kde.cache.py'
287
+	opts = Options(cachefile)
288
+	opts.AddOptions(
289
+		('PREFIX', 'root of the program installation'),
290
+
291
+		('QTDIR', ''),
292
+		('QTLIBPATH', 'path to the qt libraries'),
293
+		('QTINCLUDEPATH', 'path to the qt includes'),
294
+		('QT_UIC', 'uic command'),
295
+		('QT_MOC', 'moc command'),
296
+		('QTPLUGINS', 'uic executable command'),
297
+
298
+		('KDEDIR', ''),
299
+		('KDELIBPATH', 'path to the installed kde libs'),
300
+		('KDEINCLUDEPATH', 'path to the installed kde includes'),
301
+
302
+		('KDEBIN', 'inst path of the kde binaries'),
303
+		('KDEINCLUDE', 'inst path of the kde include files'),
304
+		('KDELIB', 'inst path of the kde libraries'),
305
+		('KDEMODULE', 'inst path of the parts and libs'),
306
+		('KDEDATA', 'inst path of the application data'),
307
+		('KDELOCALE', ''), ('KDEDOC', ''), ('KDEKCFG', ''),
308
+		('KDEXDG', ''), ('KDEXDGDIR', ''), ('KDEMENU', ''),
309
+		('KDEMIME', ''), ('KDEICONS', ''), ('KDESERV', ''),
310
+		('KDESERVTYPES', ''), ('KDEAPPS', ''),
311
+	)
312
+	opts.Update(env)
313
+
314
+	def getInstDirForResType(lenv,restype):
315
+		if len(restype) == 0 or not lenv.has_key(restype):
316
+			print RED+"unknown resource type "+restype+NORMAL
317
+			lenv.Exit(1)
318
+		else:
319
+			instdir = lenv[restype]
320
+		basedir=lenv['DESTDIR']
321
+		## support for installing into other folders when PREFIX is set - used by gnu stow
322
+		if basedir: instdir = instdir.replace(lenv['PREFIX'], basedir)
323
+		return instdir
324
+
325
+	# reconfigure when things are missing
326
+	if not env['HELP'] and (env['_CONFIGURE'] or not env.has_key('QTDIR') or not env.has_key('KDEDIR')):
327
+		detect_kde(env)
328
+		opts.Save(cachefile, env)
329
+
330
+	## set default variables, one can override them in sconscript files
331
+	env.Append(CXXFLAGS = ['-I'+env['KDEINCLUDEPATH'], '-I'+env['QTINCLUDEPATH'] ],
332
+			LIBPATH = [env['KDELIBPATH'], env['QTLIBPATH'] ])
333
+	
334
+	env['QT_AUTOSCAN'] = 1
335
+	env['QT_DEBUG']    = 0
336
+
337
+	env['MEINPROC'] = 'meinproc'
338
+	env['MSGFMT']   = 'msgfmt'
339
+
340
+	## ui file processing
341
+	def uic_processing(target, source, env):
342
+		inc_kde  ='#include <klocale.h>\n#include <kdialog.h>\n'
343
+		inc_moc  ='#include "%s"\n' % target[2].name
344
+		comp_h   ='$QT_UIC -L $QTPLUGINS -nounload -o %s %s' % (target[0].path, source[0].path)
345
+		comp_c   ='$QT_UIC -L $QTPLUGINS -nounload -tr tr2i18n -impl %s %s' % (target[0].path, source[0].path)
346
+		comp_moc ='$QT_MOC -o %s %s' % (target[2].path, target[0].path)
347
+		if env.Execute(comp_h):
348
+			return ret
349
+		dest = open( target[1].path, "w" )
350
+		dest.write(inc_kde)
351
+		dest.close()
352
+		if env.Execute( comp_c+" >> "+target[1].path ):
353
+			return ret
354
+		dest = open( target[1].path, "a" )
355
+		dest.write(inc_moc)
356
+		dest.close()
357
+		ret = env.Execute( comp_moc )
358
+		return ret
359
+	def uicEmitter(target, source, env):
360
+		adjustixes = SCons.Util.adjustixes
361
+		bs = SCons.Util.splitext(str(source[0].name))[0]
362
+		bs = os.path.join(str(target[0].get_dir()),bs)
363
+		target.append(bs+'.cpp')
364
+		target.append(bs+'.moc')
365
+		return target, source
366
+	env['BUILDERS']['Uic']=Builder(action=uic_processing,emitter=uicEmitter,suffix='.h',src_suffix='.ui')
367
+
368
+	def kcfg_buildit(target, source, env):
369
+		comp='kconfig_compiler -d%s %s %s' % (str(source[0].get_dir()), source[1].path, source[0].path)
370
+		return env.Execute(comp)
371
+	def kcfg_stringit(target, source, env):
372
+		print "processing %s to get %s and %s" % (source[0].name, target[0].name, target[1].name)
373
+	def kcfgEmitter(target, source, env):
374
+		adjustixes = SCons.Util.adjustixes
375
+		bs = SCons.Util.splitext(str(source[0].name))[0]
376
+		bs = os.path.join(str(target[0].get_dir()),bs)
377
+		# .h file is already there
378
+		target.append(bs+'.cpp')
379
+
380
+		if not os.path.isfile(str(source[0])):
381
+			print RED+'kcfg file given '+str(source[0])+' does not exist !'+NORMAL
382
+			print os.popen('pwd').read()
383
+			return target, source
384
+		kfcgfilename=""
385
+		kcfgFileDeclRx = re.compile("^[fF]ile\s*=\s*(.+)\s*$")
386
+		for line in file(str(source[0]), "r").readlines():
387
+			match = kcfgFileDeclRx.match(line.strip())
388
+			if match:
389
+				kcfgfilename = match.group(1)
390
+				break
391
+		if not kcfgfilename:
392
+			print 'invalid kcfgc file'
393
+			return 0
394
+		source.append(str(source[0].get_dir())+'/'+kcfgfilename)
395
+		return target, source
396
+
397
+	env['BUILDERS']['Kcfg']=Builder(action=env.Action(kcfg_buildit, kcfg_stringit),
398
+			emitter=kcfgEmitter, suffix='.h', src_suffix='.kcfgc')
399
+	
400
+	## MOC processing
401
+	env['BUILDERS']['Moc']=Builder(action='$QT_MOC -o $TARGET $SOURCE',suffix='.moc',src_suffix='.h')
402
+	env['BUILDERS']['Moccpp']=Builder(action='$QT_MOC -o $TARGET $SOURCE',suffix='_moc.cpp',src_suffix='.h')
403
+
404
+	## KIDL file
405
+	env['BUILDERS']['Kidl']=Builder(action= 'dcopidl $SOURCE > $TARGET || (rm -f $TARGET ; false)',
406
+			suffix='.kidl', src_suffix='.h')
407
+	## DCOP
408
+	env['BUILDERS']['Dcop']=Builder(action='dcopidl2cpp --c++-suffix cpp --no-signals --no-stub $SOURCE',
409
+			suffix='_skel.cpp', src_suffix='.kidl')
410
+	## STUB
411
+	env['BUILDERS']['Stub']=Builder(action= 'dcopidl2cpp --c++-suffix cpp --no-signals --no-skel $SOURCE',
412
+			suffix='_stub.cpp', src_suffix='.kidl')
413
+	## DOCUMENTATION
414
+	env['BUILDERS']['Meinproc']=Builder(action='$MEINPROC --check --cache $TARGET $SOURCE',suffix='.cache.bz2')
415
+	## TRANSLATIONS
416
+	env['BUILDERS']['Transfiles']=Builder(action='$MSGFMT $SOURCE -o $TARGET',suffix='.gmo',src_suffix='.po')
417
+
418
+	## Handy helpers for building kde programs
419
+	## You should not have to modify them ..
420
+
421
+	ui_ext = [".ui"]
422
+	kcfg_ext = ['.kcfgc']
423
+	header_ext = [".h", ".hxx", ".hpp", ".hh"]
424
+	cpp_ext = [".cpp", ".cxx", ".cc"]
425
+	skel_ext = [".skel", ".SKEL"]
426
+	stub_ext = [".stub", ".STUB"]
427
+
428
+	def KDEfiles(lenv, target, source):
429
+		""" Returns a list of files for scons (handles kde tricks like .skel) 
430
+		It also makes custom checks against double includes like : ['file.ui', 'file.cpp']
431
+		(file.cpp is already included because of file.ui) """
432
+
433
+		q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]')
434
+		def scan_moc(bs, file_cpp):
435
+			addfile=None
436
+			# try to find the header
437
+			h_ext=''
438
+			for n_h_ext in header_ext:
439
+				if os.path.isfile(bs+n_h_ext):
440
+					h_ext=n_h_ext
441
+					break
442
+			# We have the header corresponding to the cpp file
443
+			if h_ext:
444
+				needscan=0
445
+				# User asked for fastmoc, try to avoid scanning
446
+				if env.has_key('BKSYS_FASTMOC'):
447
+					if os.path.isfile(bs+'.moc'):
448
+						lenv.Moc(bs+h_ext)
449
+					elif os.path.isfile(bs+'_moc.cpp'):
450
+						lenv.Moccpp(bs+h_ext)
451
+						addfile=bs+'_moc.cpp'
452
+					else:
453
+						#print "need scanning "+os.getcwd()+'/'+bs+".moc"
454
+						needscan=1
455
+				else:
456
+					needscan=1
457
+				# We cannot avoid scanning the files ...
458
+				if needscan:
459
+					file_h=bs+h_ext
460
+					h_contents = open(file_h, 'rb').read()
461
+					if q_object_search.search(h_contents):
462
+						# we know now there is Q_OBJECT macro
463
+						lst = bs.split('/')
464
+						val = lst[ len(lst) - 1 ]
465
+						reg = '\n\s*#include\s*("|<)'+val+'.moc("|>)'
466
+						meta_object_search = re.compile(reg)
467
+						cpp_contents = open(file_cpp, 'rb').read()
468
+						if meta_object_search.search(cpp_contents):
469
+							lenv.Moc(file_h)
470
+						else:
471
+							lenv.Moccpp(file_h)
472
+							addfile=bs+'_moc.cpp'
473
+							print "WARNING: moc.cpp for "+bs+h_ext+" consider using #include <file.moc> instead"
474
+			return addfile
475
+
476
+		src=[]
477
+		ui_files=[]
478
+		kcfg_files=[]
479
+		other_files=[]
480
+		kidl=[]
481
+
482
+		source_=lenv.make_list(source)
483
+
484
+		# For each file, check wether it is a dcop file or not, and create the complete list of sources
485
+		for file in source_:
486
+			bs  = SCons.Util.splitext(file)[0]
487
+			ext = SCons.Util.splitext(file)[1]
488
+			if ext in skel_ext:
489
+				if not bs in kidl:
490
+					kidl.append(bs)
491
+				lenv.Dcop(bs+'.kidl')
492
+				src.append(bs+'_skel.cpp')
493
+			elif ext in stub_ext:
494
+				if not bs in kidl:
495
+					kidl.append(bs)
496
+				lenv.Stub(bs+'.kidl')
497
+				src.append(bs+'_stub.cpp')
498
+			elif ext == ".moch":
499
+				lenv.Moccpp(bs+'.h')
500
+				src.append(bs+'_moc.cpp')
501
+			elif ext in cpp_ext:
502
+				src.append(file)
503
+				if not env.has_key('NOMOCFILE'):
504
+					ret = scan_moc(bs, file)
505
+					if ret:
506
+						src.append( ret )
507
+			elif ext in ui_ext:
508
+				lenv.Uic(file)
509
+				src.append(bs+'.cpp')
510
+			elif ext in kcfg_ext:
511
+				lenv.Kcfg(file)
512
+				src.append(bs+'.cpp')
513
+			else:
514
+				src.append(file)
515
+
516
+		for base in kidl:
517
+			lenv.Kidl(base+'.h')
518
+		
519
+		# Now check against typical newbie errors
520
+		for file in ui_files:
521
+			for ofile in other_files:
522
+				if ofile == file:
523
+					print RED+"WARNING: You have included "+file+".ui and another file of the same prefix"+NORMAL
524
+					print "Files generated by uic (file.h, file.cpp must not be included"
525
+		for file in kcfg_files:
526
+			for ofile in other_files:
527
+				if ofile == file:
528
+					print RED+"WARNING: You have included "+file+".kcfg and another file of the same prefix"+NORMAL
529
+					print "Files generated by kconfig_compiler (settings.h, settings.cpp) must not be included"
530
+		return src
531
+
532
+
533
+	""" In the future, these functions will contain the code that will dump the
534
+	configuration for re-use from an IDE """
535
+	import glob
536
+	def KDEinstall(lenv, restype, subdir, files):
537
+		if env.has_key('DUMPCONFIG'):
538
+			print "<install type=\"%s\" subdir=\"%s\">" % (restype, subdir)
539
+			for i in lenv.make_list(files):
540
+				print "    <file name=\"%s\"/>" % i
541
+			print "</install>"
542
+			return
543
+
544
+		if not env['_INSTALL']:
545
+			return
546
+		dir = getInstDirForResType(lenv, restype)
547
+		install_list = lenv.bksys_install(dir+'/'+subdir, files, nodestdir=1)
548
+		return install_list
549
+
550
+	def KDEinstallas(lenv, restype, destfile, file):
551
+		if not env['_INSTALL']:
552
+			return
553
+		dir = getInstDirForResType(lenv, restype)
554
+		install_list = lenv.InstallAs(dir+'/'+destfile, file)
555
+                env.Alias('install', install_list)
556
+		return install_list
557
+
558
+	def KDEprogram(lenv, target, source, 
559
+			includes='', localshlibs='', globallibs='', globalcxxflags=''):
560
+		""" Makes a kde program 
561
+		The program is installed except if one sets env['NOAUTOINSTALL'] """
562
+		src = KDEfiles(lenv, target, source)
563
+		program_list = lenv.Program(target, src)
564
+
565
+		# we link the program against a shared library done locally, add the dependency
566
+		if not lenv.has_key('nosmart_includes'):
567
+			lenv.AppendUnique(CPPPATH=['./'])
568
+		if len(localshlibs)>0:
569
+			lst=lenv.make_list(localshlibs)
570
+			lenv.link_local_shlib(lst)
571
+			lenv.Depends( program_list, lst )
572
+			
573
+		if len(includes)>0:
574
+			lenv.KDEaddpaths_includes(includes)
575
+		if len(globallibs)>0:
576
+			lenv.KDEaddlibs(globallibs)
577
+		if len(globalcxxflags)>0:
578
+			lenv.KDEaddflags_cxx(globalcxxflags)
579
+		
580
+		if not lenv.has_key('NOAUTOINSTALL'):
581
+			KDEinstall(lenv, 'KDEBIN', '', target)
582
+		return program_list
583
+
584
+	def KDEshlib(lenv, target, source, kdelib=0, libprefix='lib', 
585
+			includes='', localshlibs='', globallibs='', globalcxxflags='', vnum=''):
586
+		""" Makes a shared library for kde (.la file for klibloader)
587
+		The library is installed except if one sets env['NOAUTOINSTALL'] """
588
+		src = KDEfiles(lenv, target, source)
589
+
590
+		if not lenv.has_key('nosmart_includes'):
591
+			lenv.AppendUnique(CPPPATH=['./'])
592
+		# we link the program against a shared library done locally, add the dependency
593
+		lst=[]
594
+		if len(localshlibs)>0:
595
+			lst=lenv.make_list(localshlibs)
596
+			lenv.link_local_shlib(lst)
597
+		if len(includes)>0:
598
+			lenv.KDEaddpaths_includes(includes)
599
+		if len(globallibs)>0:
600
+			lenv.KDEaddlibs(globallibs)
601
+		if len(globalcxxflags)>0:
602
+			lenv.KDEaddflags_cxx(globalcxxflags)
603
+
604
+		restype = 'KDEMODULE'
605
+		if kdelib==1:
606
+			restype = 'KDELIB'
607
+
608
+		library_list = lenv.bksys_shlib(target, src, getInstDirForResType(lenv, restype), libprefix, vnum, nodestdir=1)
609
+		if len(lst)>0: lenv.Depends( library_list, lst )
610
+
611
+		return library_list
612
+
613
+	def KDEstaticlib(lenv, target, source):
614
+		""" Makes a static library for kde - in practice you should not use static libraries 
615
+		1. they take more memory than shared ones
616
+		2. makefile.am needed it because of limitations
617
+		(cannot handle sources in separate folders - takes extra processing) """
618
+		if not lenv.has_key('nosmart_includes'):
619
+			lenv.AppendUnique(CPPPATH=['./'])
620
+		src = KDEfiles(lenv, target, source)
621
+		return lenv.StaticLibrary(target, src)
622
+		# do not install static libraries by default
623
+
624
+	def KDEaddflags_cxx(lenv, fl):
625
+		""" Compilation flags for C++ programs """
626
+		lenv.AppendUnique(CXXFLAGS = lenv.make_list(fl))
627
+	
628
+	def KDEaddflags_c(lenv, fl):
629
+		""" Compilation flags for C programs """
630
+		lenv.AppendUnique(CFLAGS = lenv.make_list(fl))
631
+
632
+	def KDEaddflags_link(lenv, fl):
633
+		""" Add link flags - Use this if KDEaddlibs below is not enough """
634
+		lenv.PrependUnique(LINKFLAGS = lenv.make_list(fl))
635
+
636
+	def KDEaddlibs(lenv, libs):
637
+		""" Helper function """
638
+		lenv.AppendUnique(LIBS = lenv.make_list(libs))
639
+
640
+	def KDEaddpaths_includes(lenv, paths):
641
+		""" Add new include paths """
642
+		lenv.AppendUnique(CPPPATH = lenv.make_list(paths))
643
+
644
+	def KDEaddpaths_libs(lenv, paths):
645
+		""" Add paths to libraries """
646
+		lenv.PrependUnique(LIBPATH = lenv.make_list(paths))
647
+
648
+	def KDElang(lenv, folder, appname):
649
+		""" Process translations (.po files) in a po/ dir """
650
+		transfiles = glob.glob(folder+'/*.po')
651
+		for lang in transfiles:
652
+			result = lenv.Transfiles(lang)
653
+			country = SCons.Util.splitext(result[0].name)[0]
654
+			KDEinstallas(lenv, 'KDELOCALE', country+'/LC_MESSAGES/'+appname+'.mo', result)
655
+
656
+	def KDEicon(lenv, icname='*', path='./', restype='KDEICONS', subdir=''):
657
+		"""Contributed by: "Andrey Golovizin" <grooz()gorodok()net>
658
+		modified by "Martin Ellis" <m.a.ellis()ncl()ac()uk>
659
+
660
+		Installs icons with filenames such as cr22-action-frame.png into 
661
+		KDE icon hierachy with names like icons/crystalsvg/22x22/actions/frame.png.
662
+		
663
+		Global KDE icons can be installed simply using env.KDEicon('name').
664
+		The second parameter, path, is optional, and specifies the icons
665
+		location in the source, relative to the SConscript file.
666
+
667
+		To install icons that need to go under an applications directory (to
668
+		avoid name conflicts, for example), use e.g.
669
+		env.KDEicon('name', './', 'KDEDATA', 'appname/icons')"""
670
+
671
+		if env.has_key('DUMPCONFIG'):
672
+			print "<icondirent subdir=\"%s\">" % (path+subdir)
673
+			return
674
+
675
+		type_dic = { 'action' : 'actions', 'app' : 'apps', 'device' : 
676
+			'devices', 'filesys' : 'filesystems', 'mime' : 'mimetypes' } 
677
+		dir_dic = {
678
+		'los'  :'locolor/16x16',
679
+		'lom'  :'locolor/32x32',
680
+		'him'  :'hicolor/32x32',
681
+		'hil'  :'hicolor/48x48',
682
+		'lo16' :'locolor/16x16',
683
+		'lo22' :'locolor/22x22',
684
+		'lo32' :'locolor/32x32',
685
+		'hi16' :'hicolor/16x16',
686
+		'hi22' :'hicolor/22x22',
687
+		'hi32' :'hicolor/32x32',
688
+		'hi48' :'hicolor/48x48',
689
+		'hi64' :'hicolor/64x64',
690
+		'hi128':'hicolor/128x128',
691
+		'hisc' :'hicolor/scalable',
692
+		'cr16' :'crystalsvg/16x16',
693
+		'cr22' :'crystalsvg/22x22',
694
+		'cr32' :'crystalsvg/32x32',
695
+		'cr48' :'crystalsvg/48x48',
696
+		'cr64' :'crystalsvg/64x64',
697
+		'cr128':'crystalsvg/128x128',
698
+		'crsc' :'crystalsvg/scalable'
699
+		}
700
+
701
+		iconfiles = []
702
+		for ext in "png xpm mng svg svgz".split():
703
+			files = glob.glob(path+'/'+'*-*-%s.%s' % (icname, ext))
704
+			iconfiles += files
705
+		for iconfile in iconfiles:
706
+			lst = iconfile.split('/')
707
+			filename = lst[ len(lst) - 1 ]
708
+			tmp = filename.split('-')
709
+			if len(tmp)!=3:
710
+				print RED+'WARNING: icon filename has unknown format: '+iconfile+NORMAL
711
+				continue
712
+			[icon_dir, icon_type, icon_filename]=tmp
713
+			try:
714
+				basedir=getInstDirForResType(lenv, restype)
715
+				destfile = '%s/%s/%s/%s/%s' % (basedir, subdir, dir_dic[icon_dir], type_dic[icon_type], icon_filename)
716
+			except KeyError:
717
+				print RED+'WARNING: unknown icon type: '+iconfile+NORMAL
718
+				continue
719
+			## Do not use KDEinstallas here, as parsing from an ide will be necessary
720
+			if env['_INSTALL']: 
721
+				env.Alias('install', env.InstallAs( destfile, iconfile ) )
722
+
723
+        ## This function uses env imported above
724
+        def docfolder(lenv, folder, lang, destination=""):
725
+                # folder is the folder to process
726
+                # lang is the language
727
+                # destination is the subdirectory in KDEDOC
728
+                docfiles = glob.glob(folder+"/???*.*") # file files that are at least 4 chars wide :)
729
+                # warn about errors
730
+                #if len(lang) != 2:
731
+                #       print "error, lang must be a two-letter string, like 'en'"
732
+
733
+                # when the destination is not given, use the folder
734
+                if len(destination) == 0:
735
+                        destination=folder
736
+                docbook_list = []
737
+                for file in docfiles:
738
+                        # do not process folders
739
+                        if not os.path.isfile(file):
740
+                                continue
741
+                        # do not process the cache file
742
+                        if file == 'index.cache.bz2':
743
+                                continue
744
+                        # ignore invalid files (TODO??)
745
+                        if len( SCons.Util.splitext( file ) ) <= 1 :
746
+                                continue
747
+
748
+                        ext = SCons.Util.splitext( file )[1]
749
+
750
+                        # docbook files are processed by meinproc
751
+                        if ext != '.docbook':
752
+				continue
753
+                        docbook_list.append( file )
754
+                        lenv.KDEinstall('KDEDOC', lang+'/'+destination, file)
755
+                # Now process the index.docbook files ..
756
+                if len(docbook_list) == 0:
757
+                        return
758
+                if not os.path.isfile( folder+'/index.docbook' ):
759
+                        print "Error, index.docbook was not found in "+folder+'/index.docbook'
760
+                        return
761
+	        ## Define this to 1 if you are writing documentation else to 0 :)
762
+                if env.has_key('i_am_a_documentation_writer'):
763
+                        for file in docbook_list:
764
+                                lenv.Depends( folder+'index.cache.bz2', file )
765
+                lenv.Meinproc( folder+'/index.cache.bz2', folder+'/index.docbook' )
766
+                lenv.KDEinstall( 'KDEDOC', lang+'/'+destination, folder+'/index.cache.bz2' )
767
+
768
+	#valid_targets = "program shlib kioslave staticlib".split()
769
+	import generic
770
+	class kobject(generic.genobj):
771
+		def __init__(self, val, senv=None):
772
+			if senv: generic.genobj.__init__(self, val, senv)
773
+			else: generic.genobj.__init__(self, val, env)
774
+			self.iskdelib=0
775
+		def it_is_a_kdelib(self): self.iskdelib=1
776
+		def execute(self):
777
+			self.lockchdir()
778
+			if self.orenv.has_key('DUMPCONFIG'):
779
+				print self.xml()
780
+				return
781
+			if (self.type=='shlib' or self.type=='kioslave'):
782
+				install_dir = 'KDEMODULE'
783
+				if self.iskdelib==1: install_dir = 'KDELIB'
784
+				self.instdir=getInstDirForResType(self.orenv, install_dir)
785
+				self.nodestdir=1
786
+			elif self.type=='program':
787
+				self.instdir=getInstDirForResType(self.orenv, 'KDEBIN')
788
+				self.nodestdir=1
789
+
790
+			self.src=KDEfiles(env, self.target, self.source)
791
+			generic.genobj.execute(self)
792
+			self.unlockchdir()
793
+
794
+                def xml(self):
795
+                        ret= '<compile type="%s" chdir="%s" target="%s" cxxflags="%s" cflags="%s" includes="%s" linkflags="%s" libpaths="%s" libs="%s" vnum="%s" iskdelib="%s" libprefix="%s">\n' % (self.type, self.chdir, self.target, self.cxxflags, self.cflags, self.includes, self.linkflags, self.libpaths, self.libs, self.vnum, self.iskdelib, self.libprefix)
796
+                        if self.source:
797
+                                for i in self.orenv.make_list(self.source):
798
+                                        ret += '  <source file="%s"/>\n' % i
799
+                        ret += "</compile>"
800
+                        return ret
801
+
802
+	# Attach the functions to the environment so that SConscripts can use them
803
+	SConsEnvironment.KDEprogram = KDEprogram
804
+	SConsEnvironment.KDEshlib = KDEshlib
805
+	SConsEnvironment.KDEstaticlib = KDEstaticlib
806
+	SConsEnvironment.KDEinstall = KDEinstall
807
+	SConsEnvironment.KDEinstallas = KDEinstallas
808
+	SConsEnvironment.KDElang = KDElang
809
+	SConsEnvironment.KDEicon = KDEicon
810
+
811
+	SConsEnvironment.KDEaddflags_cxx = KDEaddflags_cxx
812
+	SConsEnvironment.KDEaddflags_c = KDEaddflags_c
813
+	SConsEnvironment.KDEaddflags_link = KDEaddflags_link
814
+	SConsEnvironment.KDEaddlibs = KDEaddlibs
815
+	SConsEnvironment.KDEaddpaths_includes = KDEaddpaths_includes
816
+	SConsEnvironment.KDEaddpaths_libs = KDEaddpaths_libs
817
+
818
+	SConsEnvironment.docfolder = docfolder
819
+	SConsEnvironment.kobject = kobject
820
+

BIN
bksys/scons-mini.tar.bz2 View File


+ 6
- 0
config.h View File

@@ -0,0 +1,6 @@
1
+/* config.h -- Automatically generated by abakus.py
2
+ * Any changes you make to this file will be overwritten!
3
+ */
4
+
5
+/* HAVE_MPFR -- Defined if the MPFR library is being used. */
6
+/* #undef HAVE_MPFR */

+ 164
- 0
configure View File

@@ -0,0 +1,164 @@
1
+#!/usr/bin/env python
2
+# Configure script for abakus.  I think it's better than the sample that came
3
+# with bksys.  Feel free to do with it what you want.
4
+# By Michael Pyne <michael.pyne@kdemail.net>
5
+
6
+import sys
7
+import re
8
+
9
+BOLD="\033[1m"
10
+RED="\033[91m"
11
+GREEN="\033[92m"
12
+YELLOW="\033[93m"
13
+CYAN="\033[96m"
14
+NORMAL="\033[0m"
15
+
16
+PROGRAM_NAME='abakus'
17
+
18
+# First let's see if they asked for help.
19
+if '--help' in sys.argv:
20
+    print '''This is a configure script to prepare %s for building.
21
+
22
+You can pass the command line argument debug=1 to enable debugging for the
23
+application, which can be useful if you have problems.
24
+
25
+Otherwise, just run ./configure, and if you don't already have scons, a mini
26
+version will be installed suitable for building %s.
27
+'''.replace('%s', PROGRAM_NAME)
28
+    sys.exit(0)
29
+
30
+# Check that we have the minimum version of Python needs to run SCons.
31
+if sys.hexversion < 0x02030000:
32
+    # Use regexp for compatibility with ancient Python
33
+    version = re.split(' ', sys.version)[0]
34
+
35
+    print RED + 'Sorry, your version of Python is too old.' + NORMAL
36
+    print PROGRAM_NAME + ' requires Python 2.3 or greater to build.'
37
+    print "\nYou have Python " + version
38
+    sys.exit(1)
39
+
40
+import os
41
+
42
+# Check if scons is installed.  We can use cool Python features now that we
43
+# know we aren't using an ancient version of Python.
44
+result = os.system('scons -v > /dev/null 2>&1')
45
+scons = 'scons'
46
+
47
+if os.WEXITSTATUS(result) == 0:
48
+    print GREEN + "scons already installed." + NORMAL
49
+else:
50
+    # If we didn't find scons, don't whine to the user about it, just fix it.
51
+    print YELLOW + 'scons not installed, installing local copy.' + NORMAL
52
+
53
+    # Split this into two steps since some tars don't use j to mean bzip2
54
+    # compressed.
55
+    result = os.system('bzcat bksys/scons-mini.tar.bz2 | tar x')
56
+
57
+    if os.WEXITSTATUS(result) != 0:
58
+	print RED + 'Unable to extract scons' + NORMAL
59
+	sys.exit(2)
60
+
61
+    scons = '%s/scons' % os.getcwd()
62
+
63
+# Now we now where scons is.  Let's create a Makefile (after we configure) so
64
+# that all the user has to do is type 'make'.  Allow the user to pass command
65
+# line arguments, which will be passed to the configure process.
66
+if len(sys.argv) < 2:
67
+    options = ''
68
+else:
69
+    options = " ".join(sys.argv[1:])
70
+    # reduce is pretty cool
71
+#    options = reduce(lambda x, y: x + '\n' + y, sys.argv[1:])
72
+
73
+result = os.system(scons + ' configure ' + options)
74
+if os.WEXITSTATUS(result) != 0:
75
+    print RED + 'Unable to configure scons' + NORMAL
76
+    sys.exit(3)
77
+
78
+# Recursive generates a makefile for a directory.  If topDir is True, the
79
+# Makefile is slightly different.
80
+def generate_makefile(dir, topDir = False):
81
+
82
+    file = name + "/Makefile"
83
+
84
+    # Write out Makefile.
85
+    try:
86
+        makefile = open(file, 'w')
87
+    except IOError:
88
+        print RED + "Unable to open " + file + NORMAL
89
+        sys.exit(4)
90
+
91
+    text = '''
92
+## Makefile automatically generated by configure
93
+
94
+SCONS=$scons
95
+
96
+# $scons            : compile
97
+# $scons -c         : clean
98
+# $scons install    : install
99
+# $scons -c install : uninstall and clean
100
+
101
+# Default target: use scons to build the program
102
+all:
103
+	@$(SCONS) -Q
104
+
105
+# Debugging possibilies:
106
+# $scons --debug=explain, $scons --debug=tree
107
+
108
+# To optimize the runtime:
109
+# $scons --max-drift=1 --implicit-deps-unchanged
110
+debug:
111
+	@$(SCONS) -Q --debug=tree
112
+
113
+clean:
114
+	@$(SCONS) -c
115
+
116
+install:
117
+	@$(SCONS) install
118
+
119
+uninstall:
120
+	@$(SCONS) uninstall
121
+
122
+# This target creates a tarball of the project (in theory)
123
+dist:
124
+	@$(SCONS) dist
125
+'''
126
+
127
+    if topDir:
128
+        text = text.replace('$scons', scons)
129
+    else:
130
+        text = text.replace('$scons', scons + ' -u')
131
+
132
+    try:
133
+        print "Generating " + GREEN + file + NORMAL
134
+        makefile.write(text)
135
+        makefile.close()
136
+    except IOError:
137
+        print RED + "Unable to write to the Makefile!" + NORMAL
138
+        sys.exit(5)
139
+
140
+# Recursively generate Makefiles for convienience.
141
+for name, dirs, files in os.walk('.'):
142
+    # Don't try to build hidden directories.
143
+    remove = filter(lambda x: x[0] == '.', dirs)
144
+    for i in remove:
145
+        dirs.remove(i)
146
+
147
+    if 'SConstruct' in files:
148
+        # We're in the very top directory.
149
+        generate_makefile(name, topDir = True)
150
+
151
+        for dir in ['cache', 'bksys']:
152
+            if dir in dirs:
153
+                dirs.remove(dir)
154
+    elif 'SConscript' in files:
155
+        generate_makefile(name)
156
+
157
+# The Makefile has been written, we're pretty much done.
158
+message = '''
159
+The Makefile(s) have been generated.  Type:
160
+	`make'         to build %s, and
161
+	`make install' to install %s.
162
+'''.replace('%s', PROGRAM_NAME)
163
+
164
+print GREEN + message + NORMAL

+ 12
- 0
doc/en/SConscript View File

@@ -0,0 +1,12 @@
1
+#!/usr/bin/python
2
+
3
+Import('env')
4
+
5
+import glob
6
+
7
+sources = glob.glob("*.png")
8
+
9
+destination = 'abakus'
10
+for lang in ['en']:
11
+    for pic in sources:
12
+        env.KDEinstall('KDEDOC', "%s/%s" % (lang, destination), pic)

BIN
doc/en/abakus-degrees-mode.png View File


BIN
doc/en/abakus-dnd.png View File


BIN
doc/en/abakus-result.png View File


+ 463
- 0
doc/en/index.docbook View File

@@ -0,0 +1,463 @@
1
+<?xml version="1.0" ?>
2
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
3
+  <!ENTITY abakus "<application>abakus</application>">
4
+  <!ENTITY kappname "&abakus;">
5
+  <!ENTITY % addindex "IGNORE">
6
+  <!ENTITY % English "INCLUDE">
7
+]>
8
+
9
+<book lang="&language;">
10
+
11
+<bookinfo>
12
+<title>The &abakus; handbook</title>
13
+
14
+<authorgroup>
15
+<author>
16
+<firstname>Michael</firstname>
17
+<surname>Pyne</surname>
18
+<email>michael.pyne@kdemail.net</email>
19
+</author>
20
+<author>&J.Hall; &J.Hall.mail;</author>
21
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
22
+</authorgroup>
23
+
24
+<legalnotice>&FDLNotice;</legalnotice>
25
+
26
+<date>2005-07-06</date>
27
+<releaseinfo>0.90</releaseinfo>
28
+
29
+<abstract>
30
+<para>&abakus; is a calculator designed with computer usability in mind</para>
31
+<para>Please contact <email>michael.pyne@kdemail.net</email> for bug reports and feature requests</para>
32
+</abstract>
33
+
34
+<keywordset>
35
+<keyword>KDE</keyword>
36
+<keyword>Calculator</keyword>
37
+</keywordset>
38
+
39
+</bookinfo>
40
+
41
+<chapter id="introduction">
42
+<title>What is abakus?</title>
43
+<para>&abakus; is a calculator designed with computer usability in mind, as opposed to just being a clone of your desktop calculator. Instead of using your powerful computer to put a limited simulation of a calculator on-screen, &abakus; instead allows you to use your computer to its greater potential.</para>
44
+
45
+<para>Enough of the metaphysics, how about an example of what I'm talking about? Let's use&kcalc;, the normal &kde; calculator program as an example, trying to calculate 3 multiplied by the sine of 50 degrees. First you would do something like the following:</para>
46
+
47
+<para>1. Make sure you're in Degrees mode:</para>
48
+<para><inlinemediaobject>
49
+<imageobject>
50
+<imagedata fileref="kcalc-degrees-mode.png" format="PNG"/></imageobject>
51
+</inlinemediaobject></para>
52
+
53
+<para>2. Then, click on the <guibutton>5</guibutton> and the <guibutton>0</guibutton> buttons:</para>
54
+<para><inlinemediaobject>
55
+<imageobject>
56
+<imagedata fileref="kcalc-fifty.png" format="PNG"/></imageobject>
57
+</inlinemediaobject></para>
58
+
59
+<para>3. You would then search for the <guibutton>Sin</guibutton> button and click it, which would immediately calculate a result:</para>
60
+<para><inlinemediaobject>
61
+<imageobject>
62
+<imagedata fileref="kcalc-sine.png" format="PNG"/></imageobject>
63
+</inlinemediaobject></para>
64
+
65
+<para>4. Then, click the <guibutton>X</guibutton> button, and notice that there is no user feedback whatsoever. Even real calculators temporarily blank the display:</para>
66
+<para>
67
+<inlinemediaobject>
68
+<imageobject>
69
+<imagedata fileref="kcalc-sine.png" format="PNG"/></imageobject>
70
+</inlinemediaobject></para>
71
+
72
+<para>5. Then, we click the <guibutton>3</guibutton> button and watch as our previous result suddenly disappears. This isn't &kcalc;s fault: It has nowhere else to display the <guilabel>3</guilabel>:</para>
73
+<para><inlinemediaobject>
74
+<imageobject>
75
+<imagedata fileref="kcalc-three.png" format="PNG"/></imageobject>
76
+</inlinemediaobject></para>
77
+
78
+<para>6. Proceeding boldly forward with the faith that our previous result wasn't lost, we click the <guibutton>=</guibutton> button to perform the multiplication:</para>
79
+<para><inlinemediaobject>
80
+<imageobject>
81
+<imagedata fileref="kcalc-result.png" format="PNG"/></imageobject>
82
+</inlinemediaobject></para>
83
+
84
+<para>Although we did get the result, this is unsatisfactory for several reasons. A computer monitor has plenty of room to display text, there's no reason why you should ever be confused about what step your calculator is about to make, or whether it remembered an intermediate result. Computers are also much more powerful than your $10 desktop calculator, so there's no reason that you should be forced to type your expression in a form suitable for your calculator. Roberto Alsina picked up on this in a rant he published, <ulink url="http://www.pycs.net/lateral/stories/33.html">A Modest Usability Improvement
85
+</ulink></para>
86
+
87
+<para>Now let's try the same thing in &abakus;, which is designed to help you with your calculating, instead of bending you to its will. As with &kcalc;, extraneous portions of the GUI have been hidden.</para>
88
+
89
+<para>1. We still need to make sure we're in <guilabel>Degrees</guilabel> mode:</para>
90
+<para><inlinemediaobject>
91
+<imageobject>
92
+<imagedata fileref="abakus-degrees-mode.png" format="PNG"/></imageobject>
93
+</inlinemediaobject></para>
94
+
95
+<para>
96
+2. Now we can type <quote>3sin 50</quote>, just as we'd write it on paper. Sometimes it's better to clarify things, both for reading and to clarify your intentions to &abakus;. So you can also use the parentheses to group operations like you would on paper, and the '*' operator to explicitly multiply, like this: "3 * sin (50)":</para>
97
+<para><inlinemediaobject>
98
+<imageobject>
99
+<imagedata fileref="abakus-result.png" format="PNG"/></imageobject>
100
+</inlinemediaobject></para>
101
+
102
+<para> And we're all done! We even typed in the same expression two different ways to demonstrate how &abakus; will try very hard to guess what you're trying to calculate. You'll notice that &kcalc; and &abakus; both agree on the answer.</para>
103
+
104
+<para>If you're still reading you've probably been sold by Roberto's argument, just as I was when I started writing &abakus;. So read on, if you want to find out all that &abakus; can do for you.</para>
105
+
106
+</chapter>
107
+<chapter id="abakus-usage">
108
+<title>How to use &abakus;</title>
109
+
110
+<sect1 id="basics">
111
+<title>Basic usage</title>
112
+<para>The basic synposis is: Type your expression, and hit Enter. &abakus; will calculate the value of what you typed and display it on the screen. You can use many functions from mathematics, and even define your own functions. You can also define and use variables.</para>
113
+
114
+<para>You can define your own functions in abakus. To do so, at the expression prompt, you would type something like: <userinput>set funcname(var) = expr</userinput> and hit Enter. If all went well &abakus; will simply output <guilabel>OK</guilabel>, and you'll see your function appear in the user-defined function list. Now you can use your function as normal. If you'd like to remove your function, you can either right-click on it in the user function list and select <guilabel>Remove Function</guilabel>, or enter <userinput>remove funcname()</userinput> in the expression prompt and hit Enter. Note that you don't enter the variable name in the parentheses since only the function name is needed. (The reason you still need the parentheses is because your variables can have the same name as a function).</para>
115
+
116
+<para>You can also define your own variables. &abakus; comes with the basic mathematical constants pi (&pi;) and e (Euler's Constant) defined by default. To define your own variable, at the expression prompt you would type: <userinput><replaceable>name</replaceable> = <replaceable>value</replaceable></userinput>, or <userinput>set <replaceable>name</replaceable> = <replaceable>value</replaceable></userinput>. You will then see your variable in the list of variables. To remove your variable, either right-click on it in the list and select <guilabel>Remove Variable</guilabel>, or enter <userinput>remove varname</userinput> in the expression prompt. Notice that there are no parentheses this time. ;-)</para>
117
+
118
+<sect2 id="variables">
119
+<title>Placeholder Variables</title>
120
+
121
+<para>You may have noticed that when you type in expressions, &abakus; will show a value beginning with $ (such as $0) after the result. This is a placeholder variable. What happens is that the most recent result is always $0. The result directly before is $1, and so on. You may use the placeholder values in your expression to avoid having to re-type it or use the drag-and-drop. Note that there is a special variable defined called ans, which is the same as $0. In other words, whenever you want to reference the last expression's result, you can use $0 or ans.</para>
122
+
123
+</sect2>
124
+
125
+<sect2 id="precision">
126
+<title>Decimal Precision</title>
127
+
128
+<para>&abakus; supports high-precision arithmetic using Ariya Hidayat's hmath code from his excellent calculator <ulink url="http://speedcrunch.berlios.de/">SpeedCrunch</ulink>. You can change the displayed precision by using the <guilabel>View Menu</guilabel>, where you can select between <guilabel>Automatic precision</guilabel>, or some pre-defined precision levels. You can also select <guilabel>Custom precision</guilabel> to select your own precision (between 0-75 digits).</para>
129
+</sect2>
130
+
131
+<sect2>
132
+<title>Operators</title>
133
+<para>&abakus; supports all the standard operators like -, +, *, and /. It also supports both the ^ and ** symbols to mean exponentiation. Exponentiation is right-associative in &abakus;, meaning that 2^3^2 will return 512 instead of 64. (2^(3^2)). Operator precedence is performed as in mathematics as well (e.g. 2 + 3 * 2 and 3 * 2 + 2 both return the same answer). &abakus; also supports parentheses to group expressions for when the default operator precedence is invalid.</para>
134
+</sect2>
135
+
136
+<sect2>
137
+<title>Functions</title>
138
+<para>&abakus; has quite a few functions built-in:</para>
139
+<itemizedlist>
140
+<listitem><para>sin, cos, tan: Trigonometric functions. Supports Degrees and Radians mode.</para></listitem>
141
+<listitem><para>asin, acos, atan: Inverse trigonometric functions. Supports Degrees and Radians mode.</para></listitem>
142
+<listitem><para>abs: The absolute value of a number.</para></listitem>
143
+<listitem><para>sqrt: Square root of a number.</para></listitem>
144
+<listitem><para>ln / log: Logarithms. ln uses the "natural base", e, which log uses base 10.</para></listitem>
145
+<listitem><para>exp: Exponential. Returns e to the given power. exp(x) is equivalent to e^x.</para></listitem>
146
+<listitem><para>round, ceil, floor, int: Converts an answer to an integer. ceil rounds to the next highest integer, while floor rounds to the next lower. int simply drops the fractional part. round rounds to the nearest integer.</para></listitem>
147
+<listitem><para>frac: Returns the fractional part of a number.</para></listitem>
148
+<listitem><para>sinh, cosh, tanh: Hyperbolic trigonometric functions.</para></listitem>
149
+<listitem><para>deriv: Returns the numerical derivative of the given expression. The graphical interpretation of a derivative is the slope of the given function, at the given point. It is used like this: deriv(exp, pt). Note that since deriv takes two arguments that the parentheses are required to avoid ambiguity. For most functions, the value that deriv returns will be exact (at least within the bounds allowed by the underlying decimal representation).</para></listitem>
150
+</itemizedlist>
151
+
152
+</sect2>
153
+</sect1>
154
+
155
+</chapter>
156
+
157
+<chapter id="abakus-advanced">
158
+<title>Advanced Features</title>
159
+
160
+<para>&abakus; supports some features not typically seen in computer
161
+calculators.</para>
162
+
163
+<sect1 id="advanced-rpn-mode">
164
+<title>RPN Mode</title>
165
+<para>RPN Mode is a different input method for &abakus;, designed to emulate the
166
+input style of various old calculators which are still popular.  If you do not
167
+already know what RPN Mode is, &abakus; is not the best way to find out.
168
+However, I will give a brief description of it.
169
+</para>
170
+
171
+<para>In RPN Mode, the calculator operates from what is called the <interface>stack</interface>.
172
+Number are always added to the end of the <interface>stack</interface>, and operators always work from 
173
+the end of the <interface>stack</interface>.  One nice thing about RPN (and the
174
+reason it was developed in the first place) is that RPN expressions don't
175
+require parentheses, since the order of operations is completely unambiguous.
176
+</para>
177
+
178
+<para>So the way things work is that in RPN mode, you type in numbers and operators separated by
179
+spaces.  For each number you type, &abakus; will add to the end of the stack.
180
+Every time &abakus; encounters an operator, &abakus; will remove the appropriate
181
+number of values from the end of the stack, apply the operator, and then place
182
+the result back on the end of the stack.  &abakus; continues in this fashion
183
+until it reaches the end of your expression, and then returns whatever value
184
+is left at the top of the stack as its result.</para>
185
+
186
+<para>Let's see how this works with an example:</para>
187
+
188
+<informalexample>
189
+
190
+<para>
191
+<userinput>2 3 4 * + 2 /</userinput> would return
192
+<computeroutput>7</computeroutput>
193
+</para>
194
+
195
+<para>The way that this works is that first <userinput>2</userinput>, and then
196
+<userinput>3</userinput> are added to the end of the
197
+<interface>stack</interface>.  <userinput>4</userinput> is read and is also
198
+added to the end.  So at this point there are 3 numbers on the
199
+<interface>stack</interface>.  When &abakus; reads the operator
200
+<userinput>*</userinput>, it removes 3 and 4 from the end of the <interface>stack</interface> and
201
+multiplies them, resulting in 12.  12 is then added to the end of the <interface>stack</interface>, and
202
+the <interface>stack</interface> has 2 numbers (2 and 12).
203
+</para>
204
+