pmccabe/0000755000000000000000000000000011427053246007342 5ustar pmccabe/vifn0000755000000000000000000000100207622477726010242 0ustar #!/bin/sh if [ $# = 0 ] then echo "Usage: `basename $0` [filename/]functionname [...]" >&2 exit 2 fi exec 3<&0 while [ $# != 0 ] do fname=`dirname "$1"` fn=`basename "$1"` if [ $fname = "." ] then if [ ! -f pmccabe.out ] then pmccabe *.[Cc] >pmccabe.out fi grep ": $fn$" pmccabe.out else pmccabe $fname | grep ": $fn" fi | sed 's/[()]/ /g' | while read c1 c2 statements l1 nl filename linenumber fnname do vi +$linenumber $filename <&3 done shift done pmccabe/COPYING0000644000000000000000000010633407622477726010423 0ustar Software Copyright (C) 2003 Hewlett-Packard (Paul Bame ) GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. pmccabe/test008.ref0000644000000000000000000000102507622477726011264 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 3 3 2 2 7 test008(2): fn1 3 3 2 10 7 test008(10): fn2 6 6 6 n/a 16 Total CSL PCT NCSL PCT TOTAL FILENAME 2 12 14 88 16 test008 2 12 14 88 16 (total files: 1) pmccabe/ChangeLog0000644000000000000000000000201007622477726011124 0ustar Version 2.2 Prepare for releasing to Open Source, includes Debianizing. Version 2.1 Allow non-K&R 'const' in K&R-style function definitions (yuck). Version 2.0 Parse destructor names properly for functions implemented within their class definitions. Support declarations of classes within functions and functions within classes, recursively. Add -f and -F options to enable per-file statistics printing. Add -V option to get the current version number. Add -n option to calculate non-commented source lines directly. Output format compatible with 'anac'. Count C-preprocessor lines properly with -d and -n options, previously was not counting them as non-commented lines. Keep track of # statements in a file which are outside the scope of functions (e.g., variable declarations). Parsing 'struct foo function() {return;}' and some related constructs used to confuse the parser -- fixed. Remove a bunch of dead code. More consistent error messages. pmccabe/test002.ref0000644000000000000000000000115507622477726011262 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 1 1 test002(1): class1::class2::class3::member 1 1 1 3 1 test002(3): class1::class2::operator+= 1 1 1 5 1 test002(5): class4::operator+= 3 3 6 n/a 5 Total CSL PCT NCSL PCT TOTAL FILENAME 2 40 3 60 5 test002 2 40 3 60 5 (total files: 1) pmccabe/pkg-linux0000755000000000000000000000035707622477726011232 0ustar #!/bin/ksh mkdir -p pkg pkg/usr/local/bin pkg/usr/local/man/man1 cp -f pmccabe decomment codechanges pkg/usr/local/bin cp -f pmccabe.1 codechanges.1 pkg/usr/local/man/man1 (cd pkg && tar cvfz ../pmccabe.tar.gz $(find . -type f -print)) pmccabe/test0150000644000000000000000000000153411044155016010466 0ustar namespace Spreadsheetns { ACosFormula::ACosFormula() { //empty } ACosFormula::ACosFormula(IFormula* formula) : IOneArgFormula(formula) { if((formula->getResult() < -1) || (formula->getResult() > 1)) { throw DomainErrorException("acos is defined in de range [-1 , 1]"); } } double ACosFormula::getResult(){ if((fArgument->getResult() < -1) || (fArgument->getResult() > 1)) { throw DomainErrorException("acos is defined in de range [-1 , 1]"); } return (acos(fArgument->getResult()) * 180/DEF_PI); } } namespace foo { class bar { bar() {}; }; namespace foo1 { class bar { bar() {}; }; } int fff(void) { } }; class bar { bar() {}; }; namespace { class bar { bar() {}; }; } // Inspiration for adding namespaces and some of this test come // from Bart Van Rompaey pmccabe/cparse.c0000644000000000000000000002564311427042455010775 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #include #include #include "pmccabe.h" #include "dmain.h" /* $Id: cparse.c,v 1.24 2001/01/26 23:00:30 bame Exp $ */ int fancygettoken(char *buf, int classflag, int *line, int *nLine) { int c; char tmpbuf[256]; if ((c = gettoken(buf, line, nLine)) == T_IDENT) { if ((c = gettoken(tmpbuf, NULL, NULL)) == ':') { if ((c = ncss_Getchar()) == ':') { buf += strlen(buf); *buf++ = ':'; *buf++ = ':'; *buf = '\0'; switch (c = gettoken(tmpbuf, NULL, NULL)) { case T_OPERATOR: strcat(buf, tmpbuf); buf += strlen(buf); getoverloadedop(buf); break; case T_IDENT: /* ident::ident - could be recursive */ ncss_Ungets(tmpbuf); if ((c = fancygettoken(buf, 1, NULL, NULL)) != T_IDENT) ncss_Ungetc(c); break; case '~': /* destructor, collect the identifier */ *buf++ = c; gettoken(buf, NULL, NULL); break; default: ncss_Ungetc(c); *buf++ = '\0'; break; } } else { /* only got ':', who knows what this is */ ncss_Ungets("::"); } } else { ungettoken(c, tmpbuf); } c = T_IDENT; } else if (classflag && c == T_OPERATOR) { /* strcat(buf, tmpbuf); */ buf += strlen(buf); getoverloadedop(buf); } else if (classflag && c == '~') { *buf++ = c; c = gettoken(buf, NULL, NULL); if (c != T_IDENT) { fprintf(stderr, "fatal error file %s line %d\n", __FILE__, __LINE__); exit(3); } } return c; } int toplevelstatement(stats_t *stats) /* * At the top level of a C file, the statements are blocks of * tokens ending in either ; or are function definitions which * end in }. Interesting types of statements include class * and struct definitions - because they may contain inline functions, * and function definitions. All others are merely counted. */ { int endofstatement = FALSE; int c; char buf[1024]; int functionFirstLine = -1; int functionFirstNLine = -1; int functionDefLine; int line, nLine; buf[0] = '\0'; c = skipws(); ncss_Ungetc(c); /* gettoken eats whitespace */ while (!endofstatement && (c = fancygettoken(buf, stats->type == STATS_CLASS, &line, &nLine)) != EOF) { if (functionFirstLine == -1) { functionFirstLine = line; functionFirstNLine = nLine; } switch (c) { case T_CLASS: case T_STRUCT: case T_UNION: if (maybeclass()) { stats->nsemicolons--; endofstatement = TRUE; } break; case T_NAMESPACE: if (maybenamespace()) { /* no trailing semicolon for namespaces */ endofstatement = TRUE; } break; case '(': /* possible start of function */ functionDefLine = Line; possiblefn(stats, buf, functionFirstLine, functionDefLine, functionFirstNLine); endofstatement = TRUE; break; case '}': case ')': Exit = 2; { char _buf[100]; sprintf(_buf, "too many %c's", c); fileerror(_buf); } break; case '{': c = matchcurly(); break; case ':': /* This should catch C++ "class foo { public: } */ case ';': /* end of statement */ endofstatement = TRUE; break; default: break; } } return c; } int findchar(char fc) { int c; while ((c = ncss_Getchar()) != EOF && c != fc) { } return c; } int maybeclass() /* * We've just seen "class" at the top level in a file so * we may be entering a definition of same. If so, we want to be * on the lookout for inline functions. Return 1 if this is a * class definition else restore the function name and return 0. */ { char classname[256], dummy[256]; int isclass = 0; int c; if ((c =gettoken(classname, NULL, NULL)) == T_IDENT) { /* "class name" */ switch(c = gettoken(dummy, NULL, NULL)) { case '{': /* "class name {" */ break; case ':': /* "class name :" */ c = gettoken(dummy, NULL, NULL); if (c == ':') { /* "class name :: */ /* this is a namespace-qualified declaration since cannot have a definition like this. */ break; } else { /* "clas name : [one or more initializers]" */ while (c != '{') { c = gettoken(dummy, NULL, NULL); } } break; default: /* if we fail to get "class name [:.*] {" */ ungettoken(c, dummy); } } else if (c == '{') /* Unnamed class */ { /* "class {" */ strcpy(classname, "unnamed"); } else { /* "class BOGUS" -- perhaps this is C code using a variable "class" */ ungettoken(c, dummy); } if (isclass = (c == '{')) { stats_t *class = stats_push(classname, STATS_CLASS); while ((c = gettoken(dummy, NULL, NULL)) != '}') { if (c == EOF) { fileerror("unexpected EOF"); break; } else ungettoken(c, dummy); toplevelstatement(class); } stats_pop(class); } return isclass; } int maybenamespace() /* * We've just seen "namespace" at the top level in a file so * we may be entering a definition of same (if we next find "token {"). * Return 1 if this is a * namespace definition else restore the name and return 0. */ { char nsname[256], dummy[256]; int isns = 0; int c; if ((c = gettoken(nsname, NULL, NULL)) == T_IDENT) { /* "namespace name" */ switch(c = gettoken(dummy, NULL, NULL)) { case '{': /* "namespace name {" */ break; default: /* if we fail to get "namespace name {" */ ungettoken(c, dummy); } } else if (c == '{') /* Unnamed namespace */ { /* "namespace {" */ strcpy(nsname, "anonymous_namespace"); } else { /* "namespace BOGUS" -- is C code using a variable "namespace"? */ ungettoken(c, dummy); } if (isns = (c == '{')) { stats_t *ns = stats_push(nsname, STATS_NAMESPACE); while ((c = gettoken(dummy, NULL, NULL)) != '}') { if (c == EOF) { fileerror("unexpected EOF"); break; } else ungettoken(c, dummy); toplevelstatement(ns); } stats_pop(ns); } return isns; } void findsemicolon() { int c; while ((c = ncss_Getchar()) != EOF && c != ';') { switch (c) { case '(': c = matchparen(); break; case '{': c = matchcurly(); break; } } if (c == EOF) { Exit = 5; fileerror("expected ';' got EOF"); } } int getoverloadedop(char *buf) /* * Having just read ident::operator, try to read the operator into buf. * If the first non-WS character is a '(', the overloaded thing is a * function call. Otherwise it's some type of real operator and we * terminate normally on '('. If we read ; or { we probably should * print a warning and bail out. */ { char *savebuf = buf; char tmpbuf[256]; int c = gettoken(tmpbuf, NULL, NULL); if (c == '(') { /* overloaded function call syntax */ *buf++ = c; /* Match the paren */ while(c != ')') { if ((c = skipws()) == EOF) break; *buf++ = c; } } else if (c == T_IDENT) { /* class::operator int() */ /* Overloaded typecast */ *buf++ = '_'; *buf = '\0'; strcat(buf, tmpbuf); buf += strlen(buf); *buf++ = '('; *buf++ = ')'; *buf = '\0'; } else if (c != EOF) { *buf++ = c; while ((c = ncss_Getchar()) != EOF) { if (!ISSPACE(c)) { if (c == '(' || c == ';') { ncss_Ungetc(c); break; } else *buf++ = c; } } } *buf = '\0'; return c; } void possiblefn(stats_t *stats, const char *name, int line1, int defline, int nLine1) /* * We've just read an open parenthesis. If there's a legal identifier * in name we may be within a function definition. */ { char dummy[257]; int nstatements = 0; /* in case there's code prior to the { */ int c; if (strlen(name) == 0) { /* no function name - must not be a function - return */ findsemicolon(); } else { if ((c = matchparen()) != EOF) { c = gettoken(dummy, NULL, NULL); switch (c) { case T_CONST: if (strchr(name, ':') != NULL || stats->type == STATS_CLASS) { /* foo::foo() const ^ [;] { */ /* This'll either be a ; for a declaration or a { */ c = gettoken(dummy, NULL, NULL); break; } /* foo() const ^ char *a; { */ /*** FALL THROUGH ***/ case T_IDENT: case T_STRUCT: case T_UNION: /* if (strchr(name, ':') == NULL && stats->type != STATS_CLASS) */ { /* K&R function, T_IDENT is part of first parm defn */ /* Read up to that first '{' */ /* function foo(a, b, c) int a; */ /* ^ */ while ((c = ncss_Getchar()) != EOF && c != '{') { } } break; case '{': /* open { of the function */ break; case '(': /* wierd possibility in C++ - what we thought was the */ /* parameter list was really part of an overloaded */ /* operator overloading of an odd typecast or something. */ /* The function name will be wrong but who cares :-> */ c = matchparen(); if (c != EOF) c = gettoken(dummy, NULL, NULL); break; case ':': /* Another C++-ism: main(args): ident(args), ident(args) */ c = prefunction(&nstatements); break; } if (c == '{') { /* This really is a function */ stats_t *fn = stats_push(name, STATS_FUNCTION); fn->nfunctions = 1; fn->firstline = line1; fn->defline = defline; fn->nsemicolons = nstatements; c = countfunction(fn); fn->nLines = ncss_Line - nLine1; stats->nLines -= fn->nLines; if (!Totalsonly && !Filesonly) printstats(fn); stats_pop(fn); } } } } int prefunction(int *nstatements) /* * Handle C++ ident(args) : ident(args), ident(args). Count each * ident(args) after function declaration as a statement. */ { int c; (*nstatements)++; while((c = ncss_Getchar()) != EOF) { switch(c) { case '(': c = matchparen(); break; case ',': (*nstatements)++; break; case '{': return c; } } Exit = 9; fileerror("expected { got EOF"); return c; } int countfunction(stats_t *fn) { int nest = 1; int c; char id[257]; while (nest > 0 && (c = gettoken2(id, NULL, NULL)) != EOF) { switch (c) { case ';': fn->nsemicolons++; break; case '{': nest++; break; case '}': nest--; break; case '?': fn->nq++; break; case T_LOGICAL: fn->nor++; break; case '^': fn->nor++; /* This is XOR but I'm lazy */ break; case T_CLASS: case T_UNION: case T_STRUCT: if (maybeclass()) fn->nsemicolons--; break; default: countword(fn, c); break; } } fn->lastline = Line; if (nest > 0 /* && c == EOF */ ) { Exit = 6; fileerror("not enough }'s"); } return c; } void countword(stats_t * fn, int id) { switch (id) { case T_IF: fn->nif++; break; case T_FOR: fn->nfor++; break; case T_WHILE: fn->nwhile++; break; case T_SWITCH: fn->nswitch++; break; case T_CASE: fn->ncase++; break; } } pmccabe/testlist.ref0000644000000000000000000002502611427042455011720 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 3 6 6 test000(6): Add::Add 1 1 2 13 5 test000(13): Add::~Add 1 1 1 19 4 test000(19): Add::print 4 8 17 24 35 test000(24): Add::eval 1 1 1 60 4 test000(60): Add::modified_attributes 1 1 0 2 3 test001(2): start 1 1 0 7 6 test001(12): some_class::~some_class 1 1 0 14 1 test001(14): destructor::~destructor 1 1 0 15 1 test001(15): destructor2::~destructor 1 1 4 17 4 test001(17): main 1 1 0 22 1 test001(22): xyzzy::operator() 1 1 0 27 1 test001(27): named_class::member_function 1 1 0 32 1 test001(32): unnamed::member_function 1 1 0 35 3 test001(36): xyzzy::operator+= 1 1 1 1 1 test002(1): class1::class2::class3::member 1 1 1 3 1 test002(3): class1::class2::operator+= 1 1 1 5 1 test002(5): class4::operator+= 1 1 1 6 1 test003(6): T1::operator_long() 1 1 1 15 4 test003(15): T1::operator_long() 1 1 1 20 4 test003(20): T2::operator_long() 1 1 1 8 4 test004(8): T1::unnamed::member 1 1 1 17 4 test004(17): T1::T11::T12::member 1 1 1 22 1 test005(22): TypedValue::HasValue 1 1 1 23 1 test005(23): TypedValue::HasValue 1 1 1 24 1 test005(24): TypedValue::ResetValue 1 1 2 25 1 test005(25): TypedValue::ResetValuePtr 2 2 3 27 2 test005(27): TypedValue::Value 2 2 3 29 2 test005(29): TypedValue::ValueRef 1 1 3 31 2 test005(31): TypedValue::Value 1 1 3 34 1 test005(34): TypedValue::TypedValue 1 1 3 37 2 test005(37): TypedValue::TypedValue 1 1 2 39 1 test005(39): TypedValue::TypedValue 1 1 0 41 1 test005(41): TypedValue::DestroyValue 1 1 1 44 2 test005(45): TypedValue::HasType 1 1 1 46 1 test005(46): TypedValue::Type 1 1 1 49 1 test005(49): TypedValue::TypePtr 1 1 1 50 1 test005(50): TypedValue::TypePtr 1 1 1 58 1 test005(58): TypedValue::Assign 2 2 3 63 4 test005(65): TypedValue::print_type 1 1 3 16 11 test006/Grapher.H(16): Grapher::Grapher 1 1 0 27 1 test006/Grapher.H(27): Grapher::~Grapher 1 1 1 29 1 test006/Grapher.H(29): Grapher::xegraph 2 2 3 68 8 test006/Handler.H(68): ActionHandler::returnControl 1 1 3 77 4 test006/Handler.H(77): ActionHandler::ActionHandler 1 1 1 83 1 test006/Handler.H(83): ActionHandler::target 1 1 1 84 1 test006/Handler.H(84): ActionHandler::target 2 2 2 85 1 test006/Handler.H(85): ActionHandler::targetted 1 1 2 89 4 test006/Handler.H(89): ActionHandler::init 1 1 3 94 6 test006/Handler.H(94): ActionHandler::takeCharge 1 1 2 101 4 test006/Handler.H(101): ActionHandler::abort 1 1 1 117 4 test006/Handler.H(117): MotionHandler::initializeData 1 1 1 122 4 test006/Handler.H(122): MotionHandler::updateData 1 1 3 127 5 test006/Handler.H(127): MotionHandler::startMotion 1 1 4 132 6 test006/Handler.H(132): MotionHandler::updateMotion 1 1 4 138 6 test006/Handler.H(138): MotionHandler::endMotion 1 1 0 145 1 test006/Handler.H(145): MotionHandler::drawGhost 1 1 0 146 1 test006/Handler.H(146): MotionHandler::doIt 1 1 1 148 4 test006/Handler.H(148): MotionHandler::MotionHandler 1 1 1 155 1 test006/Handler.H(155): MotionHandler::isInitialEvent 1 1 1 156 1 test006/Handler.H(156): MotionHandler::isOkInitialTarget 1 1 1 157 1 test006/Handler.H(157): MotionHandler::isOkFinalTarget 1 1 3 174 6 test006/Handler.H(174): ArcHandler::indicateInitialTarget 1 1 1 180 4 test006/Handler.H(180): ArcHandler::indicateNoTarget 1 1 1 184 4 test006/Handler.H(184): ArcHandler::indicateFinalTarget 1 1 1 188 3 test006/Handler.H(188): ArcHandler::indicatePreviousCursor 4 4 6 192 15 test006/Handler.H(192): ArcHandler::drawGhost 1 1 1 208 4 test006/Handler.H(208): ArcHandler::isInitialEvent 2 2 2 213 4 test006/Handler.H(213): ArcHandler::isOkInitialTarget 2 2 2 217 4 test006/Handler.H(217): ArcHandler::isOkFinalTarget 1 1 2 227 5 test006/Handler.H(227): ArcHandler::ArcHandler 1 1 1 232 4 test006/Handler.H(232): ArcHandler::~ArcHandler 1 1 6 250 10 test006/Handler.H(250): ArcMaker::initializeData 2 2 6 260 10 test006/Handler.H(260): ArcMaker::startMotion 10 10 23 271 37 test006/Handler.H(271): ArcMaker::updateMotion 4 4 6 309 11 test006/Handler.H(309): ArcMaker::endMotion 1 1 4 321 10 test006/Handler.H(321): ArcMaker::doIt 2 2 1 332 4 test006/Handler.H(332): ArcMaker::isOkInitialTarget 1 1 1 336 4 test006/Handler.H(336): ArcMaker::isOkFinalTarget 1 1 1 342 4 test006/Handler.H(342): ArcMaker::ArcMaker 2 2 1 356 4 test006/Handler.H(356): ArcChanger::isOkInitialTarget 2 2 1 360 4 test006/Handler.H(360): ArcChanger::isOkFinalTarget 1 1 8 365 12 test006/Handler.H(365): ArcChanger::initializeData 2 2 6 378 12 test006/Handler.H(378): ArcChanger::startMotion 6 6 18 391 30 test006/Handler.H(391): ArcChanger::updateMotion 3 3 6 422 11 test006/Handler.H(422): ArcChanger::endMotion 1 1 1 436 4 test006/Handler.H(436): ArcChanger::ArcChanger 2 2 2 451 8 test006/Handler.H(451): NodeMaker::drawGhost 1 1 1 459 4 test006/Handler.H(459): NodeMaker::isInitialEvent 2 2 2 464 4 test006/Handler.H(464): NodeMaker::isOkInitialTarget 1 1 2 469 5 test006/Handler.H(469): NodeMaker::initializeData 1 1 2 474 5 test006/Handler.H(474): NodeMaker::updateData 1 1 1 482 4 test006/Handler.H(482): NodeMaker::NodeMaker 1 1 1 515 3 test006/Handler.H(515): Selector::deselect 2 2 6 519 10 test006/Handler.H(519): Selector::updateData 2 2 1 530 5 test006/Handler.H(530): Selector::isInitialEvent 1 1 1 536 5 test006/Handler.H(536): Selector::isOkInitialTarget 1 1 4 543 7 test006/Handler.H(543): Selector::Selector 1 1 3 570 10 test006/Handler.H(570): SweepSelector::updateData 2 2 7 581 13 test006/Handler.H(581): SweepSelector::startMotion 2 2 5 595 7 test006/Handler.H(595): SweepSelector::updateMotion 2 2 7 603 10 test006/Handler.H(603): SweepSelector::endMotion 2 2 2 616 8 test006/Handler.H(616): SweepSelector::drawGhost 1 1 1 625 4 test006/Handler.H(625): SweepSelector::isInitialEvent 1 1 1 630 4 test006/Handler.H(630): SweepSelector::isOkInitialTarget 1 1 1 636 4 test006/Handler.H(636): SweepSelector::SweepSelector 1 1 1 658 4 test006/Handler.H(658): SubgraphSelector::isInitialEvent 2 2 1 663 4 test006/Handler.H(663): SubgraphSelector::isOkInitialTarget 1 1 1 669 4 test006/Handler.H(669): SubgraphSelector::SubgraphSelector 1 1 0 681 1 test006/Handler.H(681): ItemMover::startMove 1 1 0 682 1 test006/Handler.H(682): ItemMover::updateMove 1 1 0 683 1 test006/Handler.H(683): ItemMover::endMove 2 2 1 685 3 test006/Handler.H(685): ItemMover::isOkInitialTarget 1 1 1 689 4 test006/Handler.H(689): ItemMover::ItemMover 1 1 4 706 6 test006/Handler.H(706): NodeMover::startMove 2 2 8 712 11 test006/Handler.H(712): NodeMover::updateMove 1 1 1 723 3 test006/Handler.H(723): NodeMover::endMove 1 1 1 728 4 test006/Handler.H(728): NodeMover::NodeMover 3 3 1 740 4 test006/Handler.H(740): SelectionMover::isOkInitialTarget 1 1 1 746 4 test006/Handler.H(746): SelectionMover::SelectionMover 1 1 1 758 4 test006/Handler.H(758): MenuHandler::MenuHandler 1 1 1 31 1 test006/NodeArc.H(31): LabelledNode::~LabelledNode 1 1 1 33 1 test006/NodeArc.H(33): LabelledNode::label 1 1 1 37 1 test006/NodeArc.H(37): LabelledNode::shapeType 1 1 1 39 1 test006/NodeArc.H(39): LabelledNode::borderWidth 1 1 1 40 1 test006/NodeArc.H(40): LabelledNode::borderWidth 1 1 1 42 1 test006/NodeArc.H(42): LabelledNode::xeNode 1 1 1 43 1 test006/NodeArc.H(43): LabelledNode::xeNode 2 2 5 107 10 test006/NodeArc.H(107): LabelledArc::arcContains 2 2 7 118 13 test006/NodeArc.H(118): LabelledArc::labelContains 1 1 3 134 6 test006/NodeArc.H(134): LabelledArc::getLabelOrigin 2 2 5 141 10 test006/NodeArc.H(141): LabelledArc::arrowPoints 1 1 6 152 9 test006/NodeArc.H(152): LabelledArc::arrowBoundingBox 4 4 9 162 12 test006/NodeArc.H(162): LabelledArc::arcBoundingBox 2 2 5 179 9 test006/NodeArc.H(179): LabelledArc::drawArrow 1 1 1 200 1 test006/NodeArc.H(200): LabelledArc::owner 1 1 1 202 1 test006/NodeArc.H(202): LabelledArc::getLabel 1 1 1 205 1 test006/NodeArc.H(205): LabelledArc::getLabelColor 1 1 1 208 1 test006/NodeArc.H(208): LabelledArc::getLabelVisible 1 1 3 234 1 test006/NodeArc.H(234): SiblingList::SiblingList 1 1 1 235 1 test006/NodeArc.H(235): SiblingList::~SiblingList 1 1 1 237 1 test006/NodeArc.H(237): SiblingList::count 1 1 1 238 1 test006/NodeArc.H(238): SiblingList::max 3 3 8 244 11 test006/NodeArc.H(244): SiblingList::isSibling 5 5 18 279 28 test006/NodeArc.H(279): RankedArc::arrowPoints 2 2 2 308 3 test006/NodeArc.H(308): RankedArc::computeRank 2 2 2 312 1 test006/NodeArc.H(312): RankedArc::selfish 8 8 28 314 52 test006/NodeArc.H(314): RankedArc::arcContains 4 4 9 369 15 test006/NodeArc.H(369): RankedArc::getLabelOrigin 6 6 27 385 40 test006/NodeArc.H(385): RankedArc::arcBoundingBox 3 3 8 426 14 test006/NodeArc.H(426): RankedArc::drawArc 10 10 27 441 43 test006/NodeArc.H(441): RankedArc::drawRankedArc 6 6 21 485 36 test006/NodeArc.H(485): RankedArc::drawArrow 2 2 3 526 7 test006/NodeArc.H(526): RankedArc::~RankedArc 5 5 10 1 8 test007(1): a 5 5 10 9 8 test007(9): a 5 5 10 17 8 test007(17): a 5 5 10 25 8 test007(25): a 3 3 2 2 7 test008(2): fn1 3 3 2 10 7 test008(10): fn2 1 1 1 13 1 test009(13): function1/class1::amember/class2::bmember 2 2 4 9 10 test009(9): function1/class1::amember 1 1 2 4 20 test009(5): function1 1 1 1 2 5 test011(3): function1 1 1 1 8 5 test011(9): function2 1 1 1 14 5 test011(15): function3 1 1 2 1 6 test013(1): foo 2 2 1 2 6 test014(3): main 1 1 0 2 3 test015(2): Spreadsheetns::ACosFormula::ACosFormula 3 3 3 6 5 test015(6): Spreadsheetns::ACosFormula::ACosFormula 3 3 3 12 6 test015(12): Spreadsheetns::ACosFormula::getResult 1 1 0 21 1 test015(21): foo::bar::bar 1 1 0 25 1 test015(25): foo::foo1::bar::bar 1 1 0 28 2 test015(28): foo::fff 1 1 0 32 1 test015(32): bar::bar 1 1 0 36 1 test015(36): anonymous_namespace::bar::bar 1 1 1 5 1 test016(5): Foo::Foo 1 1 1 10 1 test016(10): Foo::after_potential_parsing_hang 300 304 642 n/a 1759 Total CSL PCT NCSL PCT TOTAL FILENAME 10 16 54 84 64 test000 9 24 28 76 37 test001 2 40 3 60 5 test002 6 25 18 75 24 test003 1 4 22 96 23 test004 32 31 71 69 103 test005 11 34 21 66 32 test006/Grapher.H 151 20 619 80 770 test006/Handler.H 99 18 440 82 539 test006/NodeArc.H 0 0 32 100 32 test007 2 12 14 88 16 test008 3 13 20 87 23 test009 1 14 6 86 7 test010 3 17 15 83 18 test011 0 0 1 100 1 test012 0 0 6 100 6 test013 1 14 6 86 7 test014 5 12 35 88 40 test015 4 33 8 67 12 test016 340 19 1419 81 1759 (total files: 19) pmccabe/Makefile0000644000000000000000000000225107622477726011021 0ustar # Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later CFILES=\ cparse.c dmain.c gettoken.c nmain.c pmccabe.c \ getopt.c io.c OFILES=$(CFILES:.c=.o) INCLUDES=config.h dmain.h getopt.h pmccabe.h ###############{ # On HP-UX you will have to change this INSTALL = install -o root -g root DESTDIR = PROGS = codechanges pmccabe decomment vifn MANPGS = codechanges.1 pmccabe.1 vifn.1 decomment.1 DOCS = TODO ChangeLog COPYING PMOBJS = cparse.o \ dmain.o \ gettoken.o \ io.o \ nmain.o \ pmccabe.o all: $(PROGS) test test: $(PROGS) ./testsuite pmccabe: $(PMOBJS) $(CC) $(CFLAGS) -o pmccabe $(PMOBJS) clean: rm -f *.[oa] pmccabe decomment *.out */*.out install: $(PROGS) $(MANPGS) $(DOCS) $(INSTALL) -d $(DESTDIR)/usr/share/doc/pmccabe \ $(DESTDIR)/usr/share/man/man1 \ $(DESTDIR)/usr/bin $(INSTALL) -m 644 $(MANPGS) $(DESTDIR)/usr/share/man/man1 #$(INSTALL) -m 644 $(DOCS) $(DESTDIR)/usr/share/doc/pmccabe $(INSTALL) -m 755 $(PROGS) $(DESTDIR)/usr/bin ###############} getopt.o : config.h getopt.h dmain.o \ io.o : dmain.h pmccabe.h cparse.o \ gettoken.o \ nmain.o : pmccabe.h dmain.h pmccabe.o : pmccabe.h getopt.h pmccabe/pdiff0000755000000000000000000000407511427043346010366 0ustar #!/bin/ksh echo "@(#) $Id: pdiff,v 1.2 1998/07/21 18:53:59 bame Exp $" >&2 cycocvt() { awk 'BEGIN {OFS="\t"}{print $8 "/" $9, $1, $2, $3, $7}' } case $# in 2) olddir=$1; newdir=$2; usefind=true;; 4) olddir=$1; oldlist=$2; newdir=$3; newlist=$4; usefind=false;; *) echo "Usage: $0 old-code-directory new-code-directory" >&2 echo "Usage: $0 old-code-directory old-files-list new-code-directory new-files-list" >&2 exit 2 ;; esac pmccabe -V >&2 printf 'Analyzing %s ...' "$olddir" >&2 if $usefind then (cd $olddir && find . -type f -name '*.[cChH]*' -print | xargs pmccabe -C) else (cd $olddir && cat $oldlist | xargs pmccabe -C) fi | cycocvt | sort >old.1 printf "\nAnalyzing %s ..." "$newdir" >&2 if $usefind then (cd $newdir && find . -type f -name '*.[cChH]*' -print | xargs pmccabe -C) else (cd $newdir && cat $newlist | xargs pmccabe -C) fi | cycocvt | sort >new.1 echo >&2 echo >&2 { echo "@@@@@ common" join old.1 new.1 echo "@@@@@ old" join -v 1 old.1 new.1 echo "@@@@@ new" join -v 2 old.1 new.1 } | awk ' BEGIN { OFS = "\t" print "", "Modified McCabe Cyclomatic Complexity" print "", "| Traditional McCabe Cyclomatic Complexity" print "", "| | # Statements in function" print "", "| | | # lines in function" print "", "+-------+--------+------+---------------file name/function name" } ($1 == "@@@@@") { file = $2; next } (file == "common") { print "", total($6 - $2, $7 - $3, $8 - $4, $9 - $5), $1 } (file == "old") { print "Deleted", total(-$2, -$3, -$4, -$5), $1 } (file == "new") { print "New", total($2, $3, $4, $5), $1 } function total(m1, m2, statements, lines, s) { tm1 += m1 tm2 += m2 tstatements += statements tlines += lines if (m1 > 0) s = s "+"; s = s m1 "\t"; if (m2 > 0) s = s "+"; s = s m2 "\t"; if (statements > 0) s = s "+"; s = s statements "\t"; if (lines > 0) s = s "+"; s = s lines "\t"; return s } END { print "-----", total(tm1, tm2, tstatements, tlines), "Total" } ' pmccabe/testsuite0000755000000000000000000000116311427042455011322 0ustar #!/bin/sh # $Id: testsuite,v 1.7 2001/10/25 23:51:52 bame Exp $ testlist=' test000 test001 test002 test003 test004 test005 test006/*.H test007 test008 test009 test010 test011 test012 test013 test014 test015 test016' testlist=`echo $testlist` error=0 TEST1() { typeset f f=$1 shift ./pmccabe -vt $* > $f.out 2>&1 ./pmccabe -vnt $* >> $f.out 2>&1 if [ -f $f.ref -a -z "$REFERENCE" ] then cmp $f.ref $f.out || error=2 else echo "Creating new REFERENCE file $f.ref" mv $f.out $f.ref fi } TEST1 testlist $testlist for n in $testlist do TEST1 $n $n done exit $error pmccabe/test0140000644000000000000000000000015507761175333010502 0ustar /* test from xianjie zhang */ void main(void) { if ( test(var1, class)) { /* this line causes problem */ } } pmccabe/test0130000644000000000000000000000007007622477726010504 0ustar int foo(a, b) const char *a, *b; { a = b; return a; } pmccabe/vifn.10000644000000000000000000000167107622501721010371 0ustar .TH "vifn" 1 12Feb2003 HP .SH NAME vifn \- edit by function name rather than file name, uses vi .SH SYNOPSIS .B vifn [filename/]function-name [...] .SH DESCRIPTION .I vifn is a crude script which uses output from .IR pmccabe (1) to allow editing by function name rather than file name. When duplicate function names exist in more than one file, .I vifn cycles through each one. Use .B filename/ when multiple files contain identically-named functions and you know the one you want. .SH BUGS .I vifn uses the file "\fCpmccabe.out\fR" in the current directory, or creates it if not found by running .I pmccabe on files in the current directory. Maybe this isn't really a bug, but it could be better. .P .I vifn does not use the \fC$EDITOR\fR environment variable only because there are editors which misunderstand .IR vi 's .B +line convention for starting the editor positioned at a specific line. .SH AUTHOR Paul Bame .SH "SEE ALSO" .IR pmccabe (1) pmccabe/pmccabe.html0000644000000000000000000001573407622477726011653 0ustar HP-UX 9.03 manual page entry for pmccabe


 pmccabe(1)                                                       pmccabe(1)
                                   HP-GJD



 NAME
      pmccabe - calculate McCabe cyclomatic complexity for C and C++
      programs

 SYNOPSIS
      pmccabe [-vdCbtT?] [file(s)]


 DESCRIPTION
      pmccabe processes the named files, or standard input if none are
      named, calculating statistics including McCabe cyclomatic complexity
      for each function found.  The files are expected to be either C (ANSI
      or K&R) or C++.


      -?   Print an informative usage message.

      -v   Print column headers

      -d   Intended to help count non-commented source lines via something
           like:

           pmccabe -d *.c | grep -v '^[<blank><tab>]*$' | wc -l

           Comments and cpp directives are removed, string literals are
           replaced by STRINGLITERAL, character constants are replaced by
           CHARLITERAL.  The resulting source code is much easier to parse.
           This is the first step performed by pmccabe so that its parser
           can be simpler.

      -C   Custom output format - don't use it.

      -b   Output format compatible with softbuild.  Numerical sorting on
           this format is possible using:

           sort -n +1 -t%

      -t   Print column totals.  Note the total number of lines is *NOT* the
           number of non-commented source lines - in fact it may not be very
           useful at all.

      -T   Print column totals *ONLY*.


    Parsing
      pmccabe ignores all cpp preprocessor directives - calculating the
      complexity of the appearance of the code rather than the complexity
      after the preprocessor mangles the code.  This is especially important
      since simple things like getchar(3) expand into macros which increase
      complexity.




                                    - 1 -          Formatted:  June 29, 1998






 pmccabe(1)                                                       pmccabe(1)
                                   HP-GJD



    Output Format
      A line is written to standard output for each function found of the
      form:


           5       6       11      34      27      gettoken.c(35): matchparen

      Column 1 contains cyclomatic complexity calculated by adding 1 (for
      the function) to the occurences of for, if, while, switch, &&, ||, and
      ?.  Unlike "normal" McCabe cyclomatic complexity, each case in a
      switch statement is not counted as additional complexity.  This
      treatment of switch statements and complexity may be more useful than
      the "normal" measure for judging maintenance effort and code
      difficulty.

      Column 2 is the cyclomatic complexity calculated in the "usual" way
      with regard to switch statements.  Specifically it is calculated as in
      column 1 but counting each case rather than the switch and may be more
      useful than column 1 for judging testing effort.

      Column 3 contains a statement count.  It is calculated by adding each
      occurence of for,if,while, switch, and semicolon within the function.
      One possible surprise is that for statements have a minimum statement
      count of 3.  This is realistic since for(A; B; C){...} is really
      shorthand for

        A;
        while (B)
        {
          ...
          C;
        }

      Column 4 contains the first line number in the function.  This is not
      necessarily the same line on which the function name appears.

      Column 5 is the number of lines of the function, from the number in
      column 4 through the line containing the closing curly brace.

      The final column contains the file name, line number on which the
      function name occurs, and the name of the function.

 APPLICATIONS
      The obvious application of pmccabe is illustrated by the following
      which gives a list of the "top ten" most complex functions:


           pmccabe *.c | sort -nr | head -10

      Many files contain more than one C function and sometimes it would be
      useful to extract each function separately.  matchparen() (see example



                                    - 2 -          Formatted:  June 29, 1998






 pmccabe(1)                                                       pmccabe(1)
                                   HP-GJD



      output above) can be extracted from gettoken.c by extracting 27 lines
      starting with line 34.  This can form the basis of tools which operate
      on functions instead of files (e.g., use as a front-end for diff(1)).

 DIAGNOSTICS
      pmccabe returns a nonzero exit status if any errors occur during
      parsing.

      Error messages to standard error, usually explaining that the parser
      is confused about something, mimic normal C compiler error messages.

 WARNINGS
      pmccabe is confused by unmatched curly braces or parentheses which
      sometimes occur with hasty use of cpp directives.  In these cases a
      diagnostic is printed and the complexity results for the files named
      may be unreliable.  Most times the "#ifdef" directives may be modified
      such that the curly braces match.  Note that if pmccabe is confused by
      a cpp directive, most pretty printers will be too.  In some cases,
      preprocessing with unifdef(1) may be appropriate.

      Treatment of ?  for statement counting could perhaps be improved.

      Statement counting could arguably be improved by: counting occurences
      of the comma operator, multiple assignments, assignments within
      conditional tests, and logical conjunction.

      Destructors implemented within class definitions have no '~' in their
      name.


 AUTHOR
      Paul Bame


 SEE ALSO
      sort(1), diff(1), softbuild(1), wc(1), grep(1), unifdef(1), head(1)


















                                    - 3 -          Formatted:  June 29, 1998



Return to search page

pmccabe/test0100000644000000000000000000000010007622477726010473 0ustar # define foo a \ multi \ line \ cpp \ directive int a = 1; pmccabe/test015.ref0000644000000000000000000000154511044162325011244 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 0 2 3 test015(2): Spreadsheetns::ACosFormula::ACosFormula 3 3 3 6 5 test015(6): Spreadsheetns::ACosFormula::ACosFormula 3 3 3 12 6 test015(12): Spreadsheetns::ACosFormula::getResult 1 1 0 21 1 test015(21): foo::bar::bar 1 1 0 25 1 test015(25): foo::foo1::bar::bar 1 1 0 28 2 test015(28): foo::fff 1 1 0 32 1 test015(32): bar::bar 1 1 0 36 1 test015(36): anonymous_namespace::bar::bar 12 12 8 n/a 40 Total CSL PCT NCSL PCT TOTAL FILENAME 5 12 35 88 40 test015 5 12 35 88 40 (total files: 1) pmccabe/description0000644000000000000000000000253107622477726011630 0ustar McCabe-style complexity and line counting for C and C++ Pmccabe calculates McCabe-style cyclomatic complexity for C and C++ source code. Per-function complexity may be used for spotting likely trouble spots and for estimating testing effort. Pmccabe also includes a non-commented line counter compatible with anac, 'decomment' which only removes comments from source code; 'codechanges', a program to calculate the amount of change which has occurred between two source trees or files; and 'vifn', to invoke 'vi' given a function name rather than a file name. Pmccabe attempts to calculate the apparent complexity rather than the complexity following the C++ and/or cpp preprocessors. This causes Pmccabe to become confused with cpp constructs which cause unmatched curly braces - most of which can profitably be rewritten so they won't confuse prettyprinters anyway. Pmccabe prints C-compiler-style error messages when the parser gets confused so they may be browsed with standard tools. Two types of cyclomatic complexity are generated - one type counts each switch() statement as regardless of the number of cases included and the other more traditional measure counts each case within the switch(). Pmccabe also calculates the starting line for each function, the number of lines consumed by the function, and the number of C statements within the function. pmccabe/test0010000644000000000000000000000065207622477726010507 0ustar start() { } storage_class type some_class :: ~ some_class (){} destructor :: ~ destructor (int a) {} destructor2::~ destructor (int a) {} int main(int argc, char *argv[]): ident(args), ident(args) { body1; body2; } xyzzy :: operator () (int a, int b) {} class named_class { private: int member_function(){}; }; class /* unnamed_class */ { int member_function(){}; } xyzzy :: operator += (int a, int b) { } pmccabe/pmccabe.h0000644000000000000000000000666110660217316011114 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #ifdef __hpux #include #endif #include /* Returned by gettoken() */ #define T_BASE 256 #define T_ASSIGN (T_BASE + 0) #define T_LOGICAL (T_BASE + 1) /* non-commented nuline returned by ncss_Getchar() */ #define T_NCNULINE (T_BASE + 1) #define T_WORDS (T_BASE + 20) #define T_IDENT (T_WORDS + 2) #define T_IF (T_WORDS + 3) #define T_WHILE (T_WORDS + 4) #define T_CASE (T_WORDS + 5) #define T_SWITCH (T_WORDS + 6) #define T_FOR (T_WORDS + 7) #define T_UNION (T_WORDS + 8) #define T_STRUCT (T_WORDS + 9) #define T_CLASS (T_WORDS + 10) #define T_OPERATOR (T_WORDS + 11) #define T_CONST (T_WORDS + 12) #define T_NAMESPACE (T_WORDS + 13) #define STREQUAL(a, b) (strcmp((a),(b)) == 0) #define ZERO(x) memset(&x, 0, sizeof x) #define SHIFT(n) argc -= (n); argv += (n) /* values for stats_t.type */ #define STATS_TOTAL 0 #define STATS_FILE 1 #define STATS_FUNCTION 2 #define STATS_CLASS 3 #define STATS_NAMESPACE 4 struct stats_t { char *name; int nstatements; int nfunctions; int firstline; int lastline; int defline; int nLines; int nfor, nwhile, nswitch, ncase, nif; int nand, nor, nq; int nsemicolons; struct stats_t *prev; char type; }; typedef struct stats_t stats_t; /* can only nest this many names, including Total and file name */ #define MAXDEPTH 100 extern int Line, Linetokens, ncss_Line; extern int Exit; #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* pmccabe.c - command-line options */ extern int Cyco; extern int Softbuild; extern int Verbose; extern int Pass1; extern int Totals; extern int Totalsonly; extern int Files; extern int Filesonly; extern int Line; extern int Ncss; extern int Ncssfunction; extern int Unbuf[256]; extern int *Unptr; /* cparse.c */ int fancygettoken(char *buf, int classflag, int *line, int *nLine); int toplevelstatement(stats_t *stats); int findchar(char fc); int maybeclass(void); void findsemicolon(); int getoverloadedop(char *buf); int fancyfunction(char *buf, stats_t *fs, stats_t *fn); void possiblefn(stats_t *stats, const char *name, int line1, int defline, int nLine1); int prefunction(int *nstatements); int countfunction(stats_t *fn); void countword(stats_t *fn, int id); /* dmain.c */ int decomment(void); int decomment_files(int argc, char *argv []); int ncss_files(int argc, char *argv []); /* gettoken.c */ int matchcurly(); int matchparen(void); int skipws(void); int getsimpleident(char *buf); int gettoken(char *buf, int *line, int *nLine); int gettoken2(char *buf, int *line, int *nLine); void operatorident(char *s, int c); int identify(const char *ident); void Ungetc(int c); void ncss_Ungetc(int c); void Ungets(char *s); void ncss_Ungets(char *s); int Getchar(void); int ncss_Getchar(void); /* nmain.c */ void file(char *fname, FILE *f); void cycoprintstats(stats_t *fs, stats_t *fn); void softbuildprintstats(stats_t *fs, stats_t *fn); void printstats(stats_t *sp); void fileerror(const char *s); /* pmccabe.c */ int main(int argc, char *argv []); stats_t *stats_push(const char *name, int type); stats_t *stats_current(void); stats_t *stats_pop(stats_t *sp); void stats_accumulate(stats_t *sp); #define ISSPACE(c) ((c) == T_NCNULINE || (c) == '\n' \ || (c) == '\t' || (c) == ' ') #define ISIDENT1(c) (((c) >= 'a' && (c) <= 'z') \ || ((c) >= 'A' && (c) <= 'Z') \ || ((c) == '_')) #define ISIDENT(c) ((ISIDENT1(c)) || ((c) >= '0' && (c) <= '9')) pmccabe/test001.ref0000644000000000000000000000154307622477726011262 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 0 2 3 test001(2): start 1 1 0 7 6 test001(12): some_class::~some_class 1 1 0 14 1 test001(14): destructor::~destructor 1 1 0 15 1 test001(15): destructor2::~destructor 1 1 4 17 4 test001(17): main 1 1 0 22 1 test001(22): xyzzy::operator() 1 1 0 27 1 test001(27): named_class::member_function 1 1 0 32 1 test001(32): unnamed::member_function 1 1 0 35 3 test001(36): xyzzy::operator+= 9 9 12 n/a 37 Total CSL PCT NCSL PCT TOTAL FILENAME 9 24 28 76 37 test001 9 24 28 76 37 (total files: 1) pmccabe/pmccabe.dsp0000644000000000000000000000740207622477726011466 0ustar # Microsoft Developer Studio Project File - Name="pmccabe" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 5.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=pmccabe - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "pmccabe.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "pmccabe.mak" CFG="pmccabe - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "pmccabe - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "pmccabe - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "pmccabe - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /machine:I386 /out:"win32/pmccabe.exe" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "pmccabe - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /out:"win32/pmccabed.exe" /pdbtype:sept # SUBTRACT LINK32 /pdb:none !ENDIF # Begin Target # Name "pmccabe - Win32 Release" # Name "pmccabe - Win32 Debug" # Begin Source File SOURCE=.\cparse.c # End Source File # Begin Source File SOURCE=.\dmain.c # End Source File # Begin Source File SOURCE=.\dmain.h # End Source File # Begin Source File SOURCE=.\getopt.c # End Source File # Begin Source File SOURCE=.\getopt.h # End Source File # Begin Source File SOURCE=.\gettoken.c # End Source File # Begin Source File SOURCE=.\io.c # End Source File # Begin Source File SOURCE=.\nmain.c # End Source File # Begin Source File SOURCE=.\pmccabe.c # End Source File # Begin Source File SOURCE=.\pmccabe.h # End Source File # End Target # End Project pmccabe/test0000000644000000000000000000000210707622477726010503 0ustar #include #include Add::Add(Expr *e1, Expr *e2) { _result.TypePtr(e1->eval_type()); _left = e1; _right = e2; } Add::~Add() { delete _left; delete _right; } void Add::print(ostream &o) const { PrintBinaryExpression(o,*_left,"+",*_right); } const TypedValue &Add::eval(ValueStore &t) { const TypedValue &left = _left->eval(t); const TypedValue &right = _right->eval(t); if(!left.HasValue() || !right.HasValue()) { _result.ResetValue(); return _result; } switch(left.Type()) { case TypeInt: case TypeTime: _result = (int)left + (int)right; break; case TypeFloat: _result = (float)left + (float)right; break; case TypeString: { Str s=(const char *)left; s += (const char *)right; _result = strdup(s); } break; case TypeDate: _result = (time_t)left + (time_t)right; break; default: _result.ResetValue(); } return _result; } Boolean Add::modified_attributes(ConstCharPtrArray *arr, Boolean /*in_lvalue*/) { return _left->modified_attributes(arr,FALSE) + _right->modified_attributes(arr,FALSE); } pmccabe/test0160000644000000000000000000000052311427042455010473 0ustar class Foo { public: const struct XXX::XXX_Local_config *Get(void); /* this line caused an infinite loop looking for '{' */ Foo() : configuration(NULL) {} private: struct XXX::XXX_Local_config* configuration; /* this line caused an infinite loop looking for '{' */ void after_potential_parsing_hang() { return; } }; pmccabe/test0020000644000000000000000000000020007622477726010475 0ustar class1::class2::class3::member (int a) {stuff;} class1::class2::operator +=(int a) {impl;} class4::operator +=(int a) {impl;} pmccabe/test009.ref0000644000000000000000000000116307622477726011270 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 13 1 test009(13): function1/class1::amember/class2::bmember 2 2 4 9 10 test009(9): function1/class1::amember 1 1 2 4 20 test009(5): function1 4 4 9 n/a 23 Total CSL PCT NCSL PCT TOTAL FILENAME 3 13 20 87 23 test009 3 13 20 87 23 (total files: 1) pmccabe/test003.ref0000644000000000000000000000114107622477726011256 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 6 1 test003(6): T1::operator_long() 1 1 1 15 4 test003(15): T1::operator_long() 1 1 1 20 4 test003(20): T2::operator_long() 3 3 7 n/a 24 Total CSL PCT NCSL PCT TOTAL FILENAME 6 25 18 75 24 test003 6 25 18 75 24 (total files: 1) pmccabe/TODO0000644000000000000000000000014607622477726010052 0ustar Test namespaces -- probably won't work. Perhaps other features newer than templates will break too. pmccabe/decomment.c0000644000000000000000000001653310660217315011466 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #ifdef __hpux #define _XOPEN_SOURCE 1 #endif #ifdef __unix #include #endif #ifdef WIN32 #include "getopt.h" #endif #ifdef NEED_OPTIND extern int optind; #endif #include #include #include #include static char id[] = "$Header: /gjd/tools/pmccabe/decomment.c 1.2 2001/01/26 23:00:35 bame Exp $"; static int G_removeBlankLines = 1; static const char *G_lang; static void blankline(char *buf, char **bp) { char *ptr; *(*bp) = '\0'; if (G_removeBlankLines) { for (ptr = buf; *ptr != '\0'; ptr++) { if (!isspace(*ptr)) { fputs(buf, stdout); break; } } } else { fputs(buf, stdout); } *bp = buf; } static void decomment_sh(const char *fname, FILE *in) { register int c, c1; char outbuf[4 * 1024]; char *op = outbuf; enum { NORMAL, SH_COMMENT, DOUBLEQUOTESTRING, SINGLEQUOTESTRING } state = NORMAL; while ((c = getc(in)) != EOF) { switch (state) { case NORMAL: switch (c) { case '\'': state = SINGLEQUOTESTRING; *op++ = c; break; case '"': state = DOUBLEQUOTESTRING; *op++ = c; break; case '#': state = SH_COMMENT; break; case '\\': *op++ = c; c1 = getc(in); *op++ = c1; break; default: *op++ = c; break; } break; case SH_COMMENT: /* C++ comment */ if (c == '\n') { state = NORMAL; } break; case DOUBLEQUOTESTRING: *op++ = c; switch (c) { case '"': state = NORMAL; break; case '\\': /* handle quoted quotes */ c1 = getc(in); *op++ = c1; break; } break; case SINGLEQUOTESTRING: *op++ = c; switch (c) { case '\'': state = NORMAL; break; case '\\': getc(in); break; } break; } /* If we just stuffed a \n into the output buffer... */ if (op > outbuf && op[-1] == '\n') { blankline(outbuf, &op); } } } static void decomment_asm(const char *fname, FILE *in) { register int c, c1; char outbuf[4 * 1024]; char *op = outbuf; enum { NORMAL, ASM_COMMENT, STRINGLITERAL, CHARLITERAL } state = NORMAL; while ((c = getc(in)) != EOF) { switch (state) { case NORMAL: switch (c) { case '\'': state = CHARLITERAL; *op++ = c; break; case '"': state = STRINGLITERAL; *op++ = c; break; case ';': state = ASM_COMMENT; break; default: *op++ = c; break; } break; case ASM_COMMENT: /* C++ comment */ if (c == '\n') { state = NORMAL; } break; case STRINGLITERAL: *op++ = c; switch (c) { case '"': state = NORMAL; break; case '\\': /* handle quoted quotes */ c1 = getc(in); *op++ = c1; break; } break; case CHARLITERAL: *op++ = c; switch (c) { case '\'': state = NORMAL; break; case '\\': getc(in); break; } break; } /* If we just stuffed a \n into the output buffer... */ if (op > outbuf && op[-1] == '\n') { blankline(outbuf, &op); } } } static void decomment_c(const char *fname, FILE *in) { register int c, c1; char outbuf[4 * 1024]; char *op = outbuf; enum { NORMAL, C_COMMENT, CC_COMMENT, STRINGLITERAL, CHARLITERAL } state = NORMAL; while ((c = getc(in)) != EOF) { switch (state) { case NORMAL: switch (c) { case '\'': state = CHARLITERAL; *op++ = c; break; case '"': state = STRINGLITERAL; *op++ = c; break; case '/': c1 = getc(in); switch (c1) { case '/': state = CC_COMMENT; break; case '*': state = C_COMMENT; break; case EOF: break; default: *op++ = c; ungetc(c1, in); break; } break; default: *op++ = c; break; } break; case C_COMMENT: /* K&R C comment */ if (c == '*') { c1 = getc(in); if (c1 == '/') { state = NORMAL; } else { ungetc(c1, in); } } break; case CC_COMMENT: /* C++ comment */ if (c == '\n') { state = NORMAL; } break; case STRINGLITERAL: *op++ = c; switch (c) { case '"': state = NORMAL; break; case '\\': /* handle quoted quotes */ c1 = getc(in); *op++ = c1; break; } break; case CHARLITERAL: *op++ = c; switch (c) { case '\'': state = NORMAL; break; case '\\': getc(in); break; } break; } /* If we just stuffed a \n into the output buffer... */ if (op > outbuf && op[-1] == '\n') { blankline(outbuf, &op); } }; } static void doit(const char *fname, FILE *in) { switch(*G_lang) { case 's': decomment_sh(fname, in); break; case 'c': decomment_c(fname, in); break; case 'a': decomment_asm(fname, in); break; default: abort(); break; } } static void usage(const char *progname) { fprintf(stderr, "%s - Remove comments and blank lines from files\n\n" "Usage: %s [options] [files]\n" " -b Don't remove blank lines\n" " -l language Specify language of files\n" " c = C and C++ (default)\n" " sh = Bourne/Posix shell-like\n" " asm = Assembler\n" " NOTE: Normally the language is derived from\n" " the file name. '-l' overrides this entirely\n" " and is especially useful when %s is used as\n" " a filter.\n", progname, progname, progname); exit(2); } int main(int argc, char *argv[]) { char *langoverride = NULL; int c; while ((c = getopt(argc, argv, "bl:")) != EOF) { switch (c) { case 'b': G_removeBlankLines = 0; break; case 'l': if (!( strcmp(optarg, "c") == 0 || strcmp(optarg, "sh") == 0 || strcmp(optarg, "asm") == 0 )) { usage(argv[0]); } langoverride = optarg; break; default: usage(argv[0]); break; } } if (optind == argc) { if (langoverride != NULL) { G_lang = langoverride; } else { G_lang = "c"; } doit("stdin", stdin); } else { while (optind < argc) { const char *fname = argv[optind]; G_lang = NULL; if (langoverride != NULL) { G_lang = langoverride; } else { const char *basename; const char *ext; if ((basename = strrchr(fname, '/')) == NULL) { basename = fname; } else { basename++; } if ((ext = strrchr(basename, '.')) != NULL) { ext++; if (*ext != '\0') { if (ext[1] == '\0') { switch(ext[0]) { case 'c': case 'C': case 'h': case 'H': G_lang = "c"; break; case 's': G_lang = "asm"; break; } } else if (ext[0] == 'C' || ext[0] == 'c') { G_lang = "c"; } else if (strstr(ext, "sh") != NULL || strstr(ext, "mak") != NULL || strstr(ext, "mk") != NULL) { G_lang = "sh"; } } } else { if (strstr(basename, "akefile") != NULL) { G_lang = "sh"; } } } if (G_lang == NULL) { G_lang = "c"; } if (strcmp(fname, "-") == 0) { doit("stdin", stdin); } else { FILE *f; if ((f = fopen(fname, "r")) == NULL) { perror(fname); continue; } doit(fname, f); fclose(f); } optind++; } } return 0; } pmccabe/test0030000644000000000000000000000030507622477726010504 0ustar class T1 { int i; operator long(){return;}; }; class T2 { float f; operator long(); }; T1::operator long() { return long(i); } T2::operator long() { return long(f); } pmccabe/decomment.10000644000000000000000000000134107622502427011400 0ustar .TH "decomment" 1 12Feb2003 HP .SH NAME decomment \- remove comments from C and C++ files .SH SYNOPSIS .B decomment [file(s)] .SH DESCRIPTION .I decomment processes the named files, or standard input if none are named, copying their contents to standard output with comments removed. Line numbers in the input file(s) and out file(s) are unchanged, that is, if \fCmain()\fR occurs on line 40 in the input, it will also appear on line 40 in the output despite comment removal. .SH APPLICATIONS \fIdecomment\fR may be used to remove comments in order to simply other programs which process source code. .SH DIAGNOSTICS No parsing-related diagnostics. .SH WARNINGS .SH AUTHOR Paul Bame .SH "SEE ALSO" .IR pmccabe (1), .IR codechanges (1) pmccabe/test0070000644000000000000000000000075007622477726010514 0ustar int a() { if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; a = 1; a = 1; } int a() { if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; a = 1; a = 1; } int a() { if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; a = 1; a = 1; } int a() { if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; if (a == 1) a = 1; a = 1; a = 1; } pmccabe/test013.ref0000644000000000000000000000077007622477726011266 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 2 1 6 test013(1): foo 1 1 3 n/a 6 Total CSL PCT NCSL PCT TOTAL FILENAME 0 0 6 100 6 test013 0 0 6 100 6 (total files: 1) pmccabe/test007.ref0000644000000000000000000000111207622477726011260 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 5 5 10 1 8 test007(1): a 5 5 10 9 8 test007(9): a 5 5 10 17 8 test007(17): a 5 5 10 25 8 test007(25): a 20 20 44 n/a 32 Total CSL PCT NCSL PCT TOTAL FILENAME 0 0 32 100 32 test007 0 0 32 100 32 (total files: 1) pmccabe/test014.ref0000644000000000000000000000077107761175333011261 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 2 2 1 2 6 test014(3): main 2 2 2 n/a 7 Total CSL PCT NCSL PCT TOTAL FILENAME 1 14 6 86 7 test014 1 14 6 86 7 (total files: 1) pmccabe/test004.ref0000644000000000000000000000106607622477726011265 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 8 4 test004(8): T1::unnamed::member 1 1 1 17 4 test004(17): T1::T11::T12::member 2 2 0 n/a 23 Total CSL PCT NCSL PCT TOTAL FILENAME 1 4 22 96 23 test004 1 4 22 96 23 (total files: 1) pmccabe/getopt.h0000644000000000000000000001054707622477726011043 0ustar /* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $CVSid: @(#)getopt.h 1.7 94/09/21 $ */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if __STDC__ #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* not __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ pmccabe/test0090000644000000000000000000000037607622477726010522 0ustar extern int bar(int); void function1() { class class1 { int amember(int i) { class class2 { int bmember(){return 1;}; } for (i = 0; i < 100; i++) bar(i); return i; }; }; class1 xx; xx.amember(100); } pmccabe/pmccabe.c0000644000000000000000000001347211427052374011110 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #ifdef __hpux /* Required for access to 'optind' for getopt() on HP-UX 9 */ #define _HPUX_SOURCE 1 #endif #include #include #include #include #include #include #include "pmccabe.h" #ifdef WIN32 #include "getopt.h" #endif #ifdef NEED_OPTIND extern int optind; #endif static char _RcsVersion[] = "@(#)REV: $Header: /gjd/tools/pmccabe/pmccabe.c 1.23 2001/01/26 23:00:34 bame Exp $"; static const char _Version[] = "@(#) pmccabe 2.6"; int Cyco = 0; int Softbuild = 0; int Verbose = 0; int Pass1 = 0; int Totals = 0; int Totalsonly = 0; int Files = 0; int Filesonly = 0; int Ncss = 0; int Ncssfunction = 0; static char Normalheader[] = "Modified McCabe Cyclomatic Complexity\n" "| Traditional McCabe Cyclomatic Complexity\n" "| | # Statements in function\n" "| | | First line of function\n" "| | | | # lines in function\n" "| | | | | filename(definition line number):function\n" "| | | | | |\n"; static char NCSSheader[] = "Modified McCabe Cyclomatic Complexity\n" "| Traditional McCabe Cyclomatic Complexity\n" "| | # Statements in function\n" "| | | First line of function\n" "| | | | # uncommented nonblank lines in function\n" "| | | | | filename(definition line number):function\n" "| | | | | |\n"; static char Usage[] = "Usage: %s [-vdCbtTfFVn]\n" "\t-V\tPrint pmccabe version information\n" "\t-v\tVerbose - print column headers (nonsense with -b or -C)\n" "\t-t\tPrint totals\n" "\t-T\tPrint totals only\n" "\tMajor Modes:\n" "\t -d\tDe-comment only - can be used to count non-commented\n" "\t \tsource lines for example.\n" "\t -n\tCount non-commented source lines\n" "\t *\tDefault mode: count complexity, #statements, etc...\n" "\t\t-C\tA custom output format\n" "\t\t-c\tCount noncommented lines/function instead of\n" "\t\t\traw lines/function\n" "\t\t-b\tAn output format compatible with softbuild and other\n" "\t\t\ttools which understand traditional compiler errors\n" "\t\t-f\tPrint per-file complexity totals\n" "\t\t-F\tPrint per-file complexity totals only\n" ; int main(int argc, char *argv[]) { int result = 0; int c; char *progname = argv[0]; /* grab command-line options */ while ((c = getopt(argc, argv, "CvbdTtfFVnc")) != EOF) { switch(c) { case 'c': Ncssfunction = 1; break; case 'C': Cyco = 1; break; case 'v': Verbose = 1; break; case 'b': Softbuild = 1; break; case 'd': Pass1 = 1; break; case 'T': Totalsonly = 1; Totals = 1; break; case 't': Totals = 1; break; case 'f': Files = 1; break; case 'F': Filesonly = 1; Files = 1; break; case 'V': puts(_Version); return 0; break; case 'n': Ncss = 1; break; case '?': default: fprintf(stderr, Usage, progname); exit(3); break; } } SHIFT(optind - 1); if (Pass1) result = decomment_files(argc, argv); else if (Ncss) result = ncss_files(argc, argv); else { stats_t *total = stats_push("Total", STATS_TOTAL); total->firstline = 1; if (Verbose && !Cyco && !Softbuild) { fputs(Ncssfunction ? NCSSheader : Normalheader, stdout); } if (argc == 1) { file("stdin", stdin); } else { while (argc > 1) { FILE *f; if ((f = fopen(argv[1], "r")) == NULL) { result = 2; perror(argv[1]); } else { file(argv[1], f); fclose(f); } SHIFT(1); } } if (Totals) { printstats(total); } } return result; } static stats_t Stats[MAXDEPTH]; int Nstats = 0; /* These are cheating */ #define STOTAL Stats[0] #define SFILE Stats[1] stats_t * stats_push(const char *name, int type) { stats_t *sp; if (Nstats == MAXDEPTH) { fprintf(stderr, "Maximum name nesting depth (%d) exceed - exit\n", MAXDEPTH); exit(3); } sp = &Stats[Nstats++]; ZERO(*sp); if (Nstats > 1) sp->prev = sp - 1; sp->name = strdup(name); sp->type = type; return sp; } stats_t * stats_current() { if (Nstats < 1) { fprintf(stderr, "stats_current() called with Nstats < 1 -- exit\n"); exit(3); } return Stats + Nstats - 1; } stats_t * stats_pop(stats_t *sp) { assert(sp != NULL); if (sp != NULL) { if (sp != stats_current()) { fprintf(stderr, "stats_pop() popped value not current value - exit\n"); exit(3); } } if (Nstats == 0) { fprintf(stderr, "stats_pop() can't pop zero-length stack - exit\n"); exit(3); } stats_accumulate(sp); free(sp->name); Nstats--; return stats_current(); } static void stats_add(stats_t *result, stats_t *sp) { result->nfor += sp->nfor; result->nwhile += sp->nwhile; result->nif += sp->nif; result->nand += sp->nand; result->nor += sp->nor; result->nq += sp->nq; result->nsemicolons += sp->nsemicolons; result->nswitch += sp->nswitch; result->ncase += sp->ncase; result->nstatements += sp->nstatements; result->nfunctions += sp->nfunctions; result->lastline += sp->lastline - sp->firstline + 1; result->nLines += sp->nLines; } void stats_accumulate(stats_t *sp) { stats_t *result; for (result = sp->prev; result != NULL; result = result->prev) { if (result->type == STATS_FILE || result->type == STATS_TOTAL) break; } if (result == NULL) { fprintf(stderr, "Error in stats_accumulate() - exit\n"); exit(3); } stats_add(result, sp); } void fileerror(const char *error) { fprintf(stderr, "\"%s\", line %d: %s\n", SFILE.name, Line, error); } pmccabe/codechanges.10000644000000000000000000000413607622502427011675 0ustar .TH "codechanges" 1 12Feb2003 HP .SH NAME codechanges \- computes the amount of code changes between two code trees or single files .SH SYNOPSIS .B codechanges [-n] old-directory new-directory .P .B codechanges [-n] old-file new-file .SH DESCRIPTION .I codechanges recursively compares the two named directories (or files) calculating new/deleted/changed lines, not including comments or blank lines, in files which appear to be source files (C, C++, shell, and Makefiles). To include comments and blank lines, use the .B -n option. .SH APPLICATIONS .I codechanges is purpose designed to measure the amount of code change between milestones in a project's life. The following output is from two stages, plus some artificial test cases, in the .I pmccabe code stream: .nf NEW DELETED CHANGED Old File, New File 11 19 4 old.pmccabe/./Makefile pmccabe/./Makefile 214 10 39 old.pmccabe/./cparse.c pmccabe/./cparse.c 463 0 0 NEWFILE pmccabe/./decomment.c 147 4 39 old.pmccabe/./dmain.c pmccabe/./dmain.c 10 0 0 NEWFILE pmccabe/./dmain.h 407 0 0 NEWFILE pmccabe/./getopt.c 48 0 0 NEWFILE pmccabe/./getopt.h 9 18 12 old.pmccabe/./gettoken.c pmccabe/./gettoken.c 18 18 15 old.pmccabe/./io.c pmccabe/./io.c 175 43 20 old.pmccabe/./nmain.c pmccabe/./nmain.c 194 11 22 old.pmccabe/./pmccabe.c pmccabe/./pmccabe.c 42 0 20 old.pmccabe/./pmccabe.h pmccabe/./pmccabe.h 0 1318 0 old.pmccabe/./test/langMode.c DELETED 24 0 0 NEWFILE pmccabe/./test006/Grapher.H 620 0 0 NEWFILE pmccabe/./test006/Handler.H 442 0 0 NEWFILE pmccabe/./test006/NodeArc.H 764 0 0 NEWFILE pmccabe/./w/parser.C 95 0 0 NEWFILE pmccabe/./w/tokens.h 4 0 0 NEWFILE pmccabe/./x.sh 3687 1441 171 TOTAL .fi .SH DIAGNOSTICS There aren't many at this time. .SH BUGS .I codechanges thinks it knows what source files are interesting and the user may not agree with its choices. It's a script and should be easy to modify. Ultimately this should probably be configurable. .P .I codechanges uses a program called .I decomment which guesses how to de-comment a file based on its file name and it's not always perfect. .SH AUTHOR Paul Bame .SH "SEE ALSO" .IR pmccabe (1), .IR decomment (1) pmccabe/test000.ref0000644000000000000000000000123207622477726011254 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 3 6 6 test000(6): Add::Add 1 1 2 13 5 test000(13): Add::~Add 1 1 1 19 4 test000(19): Add::print 4 8 17 24 35 test000(24): Add::eval 1 1 1 60 4 test000(60): Add::modified_attributes 8 12 29 n/a 64 Total CSL PCT NCSL PCT TOTAL FILENAME 10 16 54 84 64 test000 10 16 54 84 64 (total files: 1) pmccabe/test0080000644000000000000000000000020107622477726010504 0ustar /* XOR test */ fn1() { if ((a > 1) && (b > 2)) { x(1); } } fn2() { if ((a > 1) ^ (b > 2)) { x(1); } } pmccabe/test0050000644000000000000000000000613007622477726010510 0ustar #ifndef TYPEDVALUE_H #define TYPEDVALUE_H #include #include class TypedValue { const ValueType *_type; SimpleValue _simplevalue; SimpleValue *_valueptr; unsigned int _has_value:1; unsigned int _use_valueptr:1; static ValueType _StaticIntType; static ValueType _StaticFloatType; static ValueType _StaticDateType; static ValueType _StaticBooleanType; static ValueType _StaticStringType; static ValueType _StaticTimeType; public: Boolean HasValue() const {return _has_value;} void HasValue(Boolean flag) {_has_value = flag;} void ResetValue() {HasValue(FALSE);} void ResetValuePtr() {_use_valueptr=0; ResetValue();} const SimpleValue &Value() const {if(_use_valueptr) return (*_valueptr) ; else return _simplevalue;} SimpleValue &ValueRef() {if(_use_valueptr) return (*_valueptr); else re turn _simplevalue;} void Value(SimpleValue &v) {_valueptr = &v; _use_valueptr=1; HasValue(T RUE);} TypedValue() {_type = NULL; _has_value=0; _use_valueptr=0;} TypedValue(BaseType type); //TypedValue(TypedValue &); TypedValue(const ValueType *t) {_type = t; _has_value=0; _use_valueptr= 0;} TypedValue(const ValueType *t, SimpleValue *v) {_type = t; Value(*v);} ~TypedValue(); void DestroyValue() {} void Ref(TypedValue &); // set typed value to point to another typed va lue Boolean HasType() const {return _type!=NULL;} BaseType Type() const {return _type->Type();} void Type(BaseType); void TypePtr(const ValueType *t) {_type = t;} const ValueType *TypePtr() const {return _type;} Boolean operator=(const int v); Boolean operator=(const float v); Boolean operator=(const time_t v); Boolean operator=(const Boolean v); Boolean operator=(const char *s); Boolean operator=(const TypedValue &t); Boolean Assign(const char *s) {return this->operator=(s);} Boolean operator += (const TypedValue &t); boolean operator==(const TypedValue &)const; // test equality of typ e *and* value void print_type(ostream &o) const { if(_type)_type->print(o); else o << "no type";} void print_value(ostream &o) const; operator int() const; operator float() const; operator Boolean() const; operator time_t() const; operator char *() const; operator Str() const; // when value is an array, get (and create if not created) a reference to the element // returns TRUE if the element was created, FALSE otherwise Boolean GetElementReference(const char *, TypedValue &result); // when value is an array, get (but don't create) a value for the eleme nt // returns TRUE if value is put in result, FALSE otherwise Boolean GetElementValue(const char *, TypedValue &result) const; // return TRUE if element with given name exists in array Boolean FindElement(const char *); // when value is an array, remove element // returns TRUE if an element was removed, FALSE otherwise Boolean RemoveElement(const char *); // return number of elements in array long ArraySize() const; // get array indices of array value // returns TRUE if indices were put in array, FALSE otherwise Boolean GetIndices(StrArray &arr) const; friend ostream &operator<<(ostream &,const TypedValue &); }; #endif pmccabe/test012.ref0000644000000000000000000000073607622477726011267 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 0 0 1 n/a 1 Total CSL PCT NCSL PCT TOTAL FILENAME 0 0 1 100 1 test012 0 0 1 100 1 (total files: 1) pmccabe/gettoken.c0000644000000000000000000001060310660217316011324 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #include "pmccabe.h" #include "dmain.h" int matchcurly() { int c; int nest = 1; while (nest > 0 && (c = ncss_Getchar()) != EOF) { switch (c) { case '{': nest++; break; case '}': nest--; break; } } if (nest > 0 /* && c == EOF */ ) { Exit = 7; fileerror("not enough }'s"); } return c; } int matchparen() { int c; int nest = 1; while (nest > 0 && (c = ncss_Getchar()) != EOF) { switch (c) { case '(': nest++; break; case ')': nest--; break; } } if (nest > 0 /* && c == EOF */ ) { Exit = 8; fileerror("not enough )'s"); } return c; } int skipws() { int c; /* skip whitespace */ while ((c = ncss_Getchar()) != EOF && ISSPACE(c)) { } return c; } int getsimpleident(char *buf) { int c = 0; while (c != EOF) { c = ncss_Getchar(); if (ISIDENT(c)) { *buf++ = c; } else { *buf++ = '\0'; break; } } return c; } int identify(const char *ident) { int r = T_IDENT; switch(*ident) { case 'i': if (STREQUAL(ident, "if")) r = T_IF; break; case 'w': if (STREQUAL(ident, "while")) r = T_WHILE; break; case 'c': if (STREQUAL(ident, "case")) r = T_CASE; else if (STREQUAL(ident, "class")) r = T_CLASS; else if (STREQUAL(ident, "const")) r = T_CONST; break; case 's': if (STREQUAL(ident, "switch")) r = T_SWITCH; else if (STREQUAL(ident, "struct")) r = T_STRUCT; break; case 'f': if (STREQUAL(ident, "for")) r = T_FOR; break; case 'u': if (STREQUAL(ident, "union")) r = T_UNION; break; case 'o': if (STREQUAL(ident, "operator")) r = T_OPERATOR; break; case 'n': if (STREQUAL(ident, "namespace")) r = T_NAMESPACE; break; } return r; } void ungettoken(int c, char *s) { if (c >= T_WORDS) { ncss_Ungets(s); } else { ncss_Ungetc(c); } } int gettoken(char *buf, int *line, int *nLine) /* * Callers depend on the fact that gettoken() doesn't modify buf except * when T_IDENT is parsed. */ { int c; int colon = FALSE; char *startbuf = buf; /* skip whitespace */ c = skipws(); if (line != NULL) *line = Line; if (nLine != NULL) *nLine = ncss_Line; if (ISIDENT1(c)) { *buf++ = c; ncss_Ungetc(getsimpleident(buf)); c = identify(buf - 1); } return c; } int gettoken2(char *buf, int *line, int *nLine) /* * This one can additionally return T_ASSIGN and T_LOGICAL. But note * that the caller isn't given enough data to know what specifically * was parsed. */ { int c, c1, c2; int colon = FALSE; char *startbuf = buf; /* skip whitespace */ c = skipws(); if (line != NULL) *line = Line; if (nLine != NULL) *nLine = ncss_Line; switch(c) { case '*': /* OP= */ case '/': case '%': case '^': c1 = ncss_Getchar(); if (c1 == '=') { c = T_ASSIGN; } else { ncss_Ungetc(c1); } break; case '+': /* +=, ++ */ case '-': /* -=, -- */ c1 = ncss_Getchar(); if (c1 == '=' || c1 == c) { c = T_ASSIGN; } else { ncss_Ungetc(c1); } break; case '&': /* &=, && */ case '|': /* |=, || */ c1 = ncss_Getchar(); if (c1 == '=') { c = T_ASSIGN; } else if (c1 == c) { c = T_LOGICAL; } else { ncss_Ungetc(c1); } break; case '<': /* >>= */ case '>': /* <<= */ c1 = ncss_Getchar(); if (c1 == c) { c2 = ncss_Getchar(); if (c2 == '=') { c = T_ASSIGN; } else { ncss_Ungetc(c2); } } else { ncss_Ungetc(c1); } break; } if (ISIDENT1(c)) { *buf++ = c; ncss_Ungetc(getsimpleident(buf)); c = identify(buf - 1); } return c; } void operatorident(char *s, int c) /* * We're in an operator-overloaded C++ identifier. This isn't * perfect but we read until either ( or ; to guess the identifier's * name. In this pass we also replace whitespace with _ for printing. */ { while (c != EOF) { if (ISSPACE(c)) { ncss_Ungetc(skipws()); *s++ = '_'; } else if (c == '(' || c == ';') { ncss_Ungetc(c); break; } else { *s++ = c; } c = ncss_Getchar(); } if (s[-1] == '_') s[-1] = '\0'; else s[0] = '\0'; } pmccabe/debian/0000755000000000000000000000000011427053246010564 5ustar pmccabe/debian/changelog0000644000000000000000000000362011427052374012440 0ustar pmccabe (2.6) unstable; urgency=low * From Ubuntu: * Fixed 364338 pdiff script change has bug * Fixed 499589 infinite loop with namespaced struct variable declaration * Thanks to matt_hargett for bugs and patches * Fixed a problem parsing DOS-format CRLF files * Updated deb stds version and fixed some lintian warnings -- Paul Bame Fri, 06 Aug 2010 14:18:25 -0400 pmccabe (2.5) unstable; urgency=low * updated codechanges and pdiff to be bashism safe * updated test files * bump Build-Depends debhelper 3->5 -- Paul Bame Wed, 30 Jul 2008 15:21:28 -0600 pmccabe (2.4+nmu2) unstable; urgency=medium * Non-maintainer upload. * Fix bashism in codechanges /bin/sh script (Closes: #486054) -- Chris Lamb Tue, 09 Sep 2008 03:36:03 +0100 pmccabe (2.4+nmu1) unstable; urgency=medium * Non-maintainer upload. * Fix bashism in 'codechanges' script (Closes: #465351) * Bump Standards-Version to 3.7.3. -- Chris Lamb Sat, 12 Apr 2008 04:59:33 +0100 pmccabe (2.4) unstable; urgency=low * add support for C++ namespaces -- Paul Bame Mon, 13 Aug 2007 21:14:22 -0600 pmccabe (2.3-1) unstable; urgency=low * you can use "class" as an identifier in C code now. Thanks to xianjie zhang for an excellent bug report. -- Paul Bame Wed, 26 Nov 2003 12:06:55 -0700 pmccabe (2.2-3) unstable; urgency=low * tweek for running under buildd and whenever pmccabe not installed and . not in $PATH -- Paul Bame Wed, 12 Mar 2003 14:05:33 -0700 pmccabe (2.2-2) unstable; urgency=low * Tweek debian/copyright to follow policy -- Paul Bame Sun, 23 Feb 2003 13:03:18 -0700 pmccabe (2.2-1) unstable; urgency=low * Initial public release. * Closes: #177749 -- Paul Bame Tue, 17 Dec 2002 10:07:41 -0700 pmccabe/debian/copyright0000644000000000000000000000104710660355552012524 0ustar This package was debianized by Paul Bame on Tue, 17 Dec 2002 10:07:41 -0700. It was orignally downloaded from Hewlett-Packard internal software archives and is now available from http://parisc-linux.org/~bame/pmccabe/ Author(s): Paul Bame Copyright: Copyright (C) 2002 Hewlett-Packard (Paul Bame ). This software is licensed under the terms of the GNU General Public License version 2 or later. See the file GPL-2 in /usr/share/common-licenses which is part of the base-files Debian package. pmccabe/debian/rules0000755000000000000000000000440011427052374011643 0ustar #!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 by Joey Hess. # # This version is for a hypothetical package that builds an # architecture-dependant package, as well as an architecture-independent # package. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) CFLAGS += -g endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. touch configure-stamp build-arch: configure-stamp build-arch-stamp build-arch-stamp: dh_testdir $(MAKE) touch build-arch-stamp build-indep: configure-stamp build-indep-stamp build-indep-stamp: dh_testdir # Add here command to compile/build the arch indep package. # It's ok not to do anything here, if you don't need to build # anything for this package. #/usr/bin/docbook-to-man debian/pmccabe.sgml > pmccabe.1 touch build-indep-stamp build: build-arch build-indep clean: dh_testdir dh_testroot rm -f build-arch-stamp build-indep-stamp configure-stamp # Add here commands to clean up after the build process. $(MAKE) clean dh_clean install: DH_OPTIONS= install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/pmccabe. $(MAKE) install DESTDIR=$(CURDIR)/debian/pmccabe dh_movefiles --sourcedir=debian/pmccabe # Build architecture-independent files here. # Pass -i to all debhelper commands in this target to reduce clutter. binary-indep: build install # Build architecture-dependent files here. binary-arch: build install dh_testdir -a dh_testroot -a # dh_installdebconf -a dh_installdocs -a dh_installexamples -a dh_installmenu -a # dh_installlogrotate -a # dh_installemacsen -a # dh_installpam -a # dh_installmime -a # dh_installinit -a dh_installcron -a # dh_installman -a dh_installinfo -a # dh_undocumented -a dh_installchangelogs ChangeLog -a dh_strip -a dh_link -a dh_compress -a dh_fixperms -a # dh_makeshlibs -a dh_installdeb -a # dh_perl -a dh_shlibdeps -a dh_gencontrol -a dh_md5sums -a dh_builddeb -a binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure pmccabe/debian/dirs0000644000000000000000000000002107622477726011460 0ustar usr/bin usr/sbin pmccabe/debian/control0000644000000000000000000000315711427052374012176 0ustar Source: pmccabe Section: devel Priority: optional Maintainer: Paul Bame Build-Depends: debhelper (>> 5.0.0) Standards-Version: 3.9.1 Package: pmccabe Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: McCabe-style function complexity and line counting for C and C++ Pmccabe calculates McCabe-style cyclomatic complexity for C and C++ source code. Per-function complexity may be used for spotting likely trouble spots and for estimating testing effort. . Pmccabe also includes a non-commented line counter compatible with anac, 'decomment' which only removes comments from source code; 'codechanges', a program to calculate the amount of change which has occurred between two source trees or files; and 'vifn', to invoke 'vi' given a function name rather than a file name. . Pmccabe attempts to calculate the apparent complexity rather than the complexity following the C++ and/or cpp preprocessors. This causes Pmccabe to become confused with cpp constructs which cause unmatched curly braces - most of which can profitably be rewritten so they won't confuse prettyprinters anyway. Pmccabe prints C-compiler-style error messages when the parser gets confused so they may be browsed with standard tools. . Two types of cyclomatic complexity are generated - one type counts each switch() statement as regardless of the number of cases included and the other more traditional measure counts each case within the switch(). Pmccabe also calculates the starting line for each function, the number of lines consumed by the function, and the number of C statements within the function. pmccabe/debian/docs0000644000000000000000000000000507622477726011451 0ustar TODO pmccabe/debian/compat0000644000000000000000000000000211427052374011763 0ustar 5 pmccabe/test005.ref0000644000000000000000000000234407622477726011266 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 22 1 test005(22): TypedValue::HasValue 1 1 1 23 1 test005(23): TypedValue::HasValue 1 1 1 24 1 test005(24): TypedValue::ResetValue 1 1 2 25 1 test005(25): TypedValue::ResetValuePtr 2 2 3 27 2 test005(27): TypedValue::Value 2 2 3 29 2 test005(29): TypedValue::ValueRef 1 1 3 31 2 test005(31): TypedValue::Value 1 1 3 34 1 test005(34): TypedValue::TypedValue 1 1 3 37 2 test005(37): TypedValue::TypedValue 1 1 2 39 1 test005(39): TypedValue::TypedValue 1 1 0 41 1 test005(41): TypedValue::DestroyValue 1 1 1 44 2 test005(45): TypedValue::HasType 1 1 1 46 1 test005(46): TypedValue::Type 1 1 1 49 1 test005(49): TypedValue::TypePtr 1 1 1 50 1 test005(50): TypedValue::TypePtr 1 1 1 58 1 test005(58): TypedValue::Assign 2 2 3 63 4 test005(65): TypedValue::print_type 20 20 31 n/a 103 Total CSL PCT NCSL PCT TOTAL FILENAME 32 31 71 69 103 test005 32 31 71 69 103 (total files: 1) pmccabe/getopt.c0000644000000000000000000005322707622477726011040 0ustar #define HAVE_STRING_H /* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #ifdef HAVE_CONFIG_H #if defined (emacs) || defined (CONFIG_BROKETS) /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because it found this file in $srcdir). */ #include #else #include "config.h" #endif #endif #ifndef __STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include #ifdef HAVE_STRING_H #include #endif /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #endif /* GNU C library. */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #ifndef lint static char rcsid[] = "$CVSid: @(#)getopt.c 1.10 94/09/21 $"; #endif #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #ifndef __STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ static const char * _getopt_initialize (optstring) const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind = 1; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0) optstring = _getopt_initialize (optstring); if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if (nameend - nextchar == (int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, "%s: unrecognized option `--%s'\n", argv[0], nextchar); else /* +option or -option */ fprintf (stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); else fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ pmccabe/codechanges0000755000000000000000000001152411101124176011524 0ustar #!/bin/sh -f # $Header: /gjd/tools/pmccabe/codechanges 1.12 2001/10/25 23:51:46 bame Exp $ # Find a "good", e.g., "new" (circa 1988?), awk goodawk() { for AWK in gawk nawk awk do $AWK -v foo=bar 'function f() { print 1 }' >/dev/null 2>&1 && return done echo "I can't find a new enough 'awk' (tried gawk, nawk and awk) in" >&2 echo "your \$PATH to run this program -- sorry." >&2 exit 5 } FIND() { ( cd $1 && find . -type f -a \ \( \ -name *.[cC] \ -o -name *.[hH] \ -o -name *.*sh \ -o -name *.mak \ -o -name *akefile \ -o -name *.cpp \ -o -name *.cxx \ -o -name *.C \ -o -name *.cc \ -o -name *.hh \ \) -print | sort ) } parsediff() { $AWK -v dir1="$1" -v dir2="$2" ' # Skip noise lines BEGIN { printf("%s\t%s\t%s\tOld File, New File\n", "NEW", "DELETED", "CHANGED"); } (/^>/) { next } (/^ 0) { nlines++ } return nlines } ($1 == "Add") { #print "DEBUG: adding", lines, "lines from", fname eof() file1 = "NEWFILE" file2 = $2 addtotal += $3; eof() next } ($1 == "Delete") { #print "DEBUG: deleting", lines, "lines from", fname eof() file2 = "DELETED" file1 = $2 deltotal += $3; eof() next } function eof() { if (file1 != "" && (addtotal > 0 || deltotal > 0 || chgtotal > 0)) { printf("%d\t%d\t%d\t%s %s\n", addtotal, deltotal, chgtotal, file1, file2); taddtotal += addtotal; tdeltotal += deltotal; tchgtotal += chgtotal; } file1 = "" addtotal = 0; deltotal = 0; chgtotal = 0; } ($1 == "diff") { #print "DEBUG: ", $0 eof(); file1 = $(NF - 1) file2 = $(NF) next } (/c/) { n=split($0,tmparray,"c"); # do left side of c and then right leftchg = parse(tmparray[1]) + 0; rightchg = parse(tmparray[n])+ 0; if(leftchg == rightchg) { change = leftchg; } # assume that smaller side is change and the difference is add or delete else if(leftchg > rightchg) { #print "DEBUG=", leftchg, rightchg change = rightchg ; deltotal += (leftchg - rightchg) #print "deleted via change " leftchg - rightchg } else if(leftchg < rightchg) { change = leftchg addtotal += (rightchg-leftchg) #print "DEBUG<", leftchg, rightchg #print "added via change " rightchg - leftchg }; # print "change ", change, "left changed ", \ #leftchg , "right changed ", rightchg, "INPUT= ", m, $0; chgtotal += change; next } # parse if comma separated or return value if no comma function parse(str, localval, localarray,localcount) { localcount=split(str, localarray, ",") if(localcount == 1) localval = 1; else localval = (localarray[localcount]+0 - \ localarray[localcount-1] +1) #print "DEBUG return value", localval, str return(localval); } (/d/) { n=split($0,tmparray,"d"); #uses line range before the d deleted = parse(tmparray[1]); deltotal += deleted; #print "deleted " deleted, "DEBUG", $0; next } (/a/) { # print "DEBUG:", file1, file2, $0 n=split($0,tmparray,"a"); # uses line range after the a added = parse(tmparray[n]); addtotal += added; #print "added ", added , "DEBUG", m, $0; next } { print "?????????", $0 } END { eof(); printf("%d\t%d\t%d\tTOTAL\n", taddtotal, tdeltotal, tchgtotal); } ' } # Need to pick up 'decomment' PATH=$PATH:$(dirname $0) goodawk if [ X$1 = X-n ] then DECOMMENT=cat shift 1 else DECOMMENT=decomment fi if [ $# != 2 ] then cat >&2 < $TMPDIR/A $DECOMMENT $2 > $TMPDIR/B $DECOMMENT $dir2/$fname | diff -bw -- $TMPDIR/A $TMPDIR/B } | parsediff rm -fr $TMPDIR exit fi dir1=$1 dir2=$2 printf '%s' "$dir1 ..." >&2 FIND $dir1 > $TMPDIR/A printf '\n%s' "$dir2 ..." >&2 FIND $dir2 > $TMPDIR/B echo >&2 comm $TMPDIR/A $TMPDIR/B | while IFS="" read f do set -- $f fname=$1 case $f in " "*) echo "diff $dir1/$fname $dir2/$fname" $DECOMMENT $dir1/$fname > $TMPDIR/C $DECOMMENT $dir2/$fname | diff -bw -- $TMPDIR/C - ;; " "*) lines=$($DECOMMENT $dir2/$fname | wc -l) echo "Add $dir2/$fname $lines" ;; *) lines=$($DECOMMENT $dir1/$fname | wc -l) echo "Delete $dir1/$fname $lines" ;; esac done | tee $TMPDIR/D | parsediff $dir1 $dir2 rm -fr $TMPDIR pmccabe/test0120000644000000000000000000000001607622477726010503 0ustar class foo {}; pmccabe/makefile.c60000644000000000000000000000053207622477726011370 0ustar CC = CL -DMSC6 CFLAGS = -AS -G2 LDFLAGS = -F 8000 LD = CL MAKEFILE = Makefile CFILES = cparse.c \ dmain.c \ gettoken.c \ io.c \ nmain.c \ pmccabe.c OFILES = $(CFILES:.c=.obj) PROGRAM = pmccabe.exe all: $(PROGRAM) $(PROGRAM): $(OFILES) $(LD) $(CFLAGS) $(LDFLAGS) $(OFILES) -o $(PROGRAM) pmccabe/dmain.c0000644000000000000000000001243211427042455010600 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #include "dmain.h" #include "pmccabe.h" /* Global */ int ncss_Line; /* $Id: dmain.c,v 1.16 2001/01/26 23:00:32 bame Exp $ */ static int Lastc = '\n'; short Pipe[SIZE]; short *Piperead = Pipe; short *Pipewrite = Pipe; short *Pipeend = Pipe + sizeof Pipe; FILE *Input; char Inputfile[1030]; int Cppflag = 0; int decomment() { register int c, c1; enum { NORMAL, C_COMMENT, CPP, CC_COMMENT, STRINGLITERAL, CHARLITERAL} state = NORMAL; Piperead = Pipewrite = Pipe; do { if ((c = getc(Input)) == EOF) { PUTCHAR(EOF); break; } if (c == '\r') continue; switch (state) { case NORMAL: switch(c) { case '#': if (Lastc == '\n') { state = CPP; if (Cppflag) PUTS("cpp"); } else { PUTCHAR(c); } break; case '\'': state = CHARLITERAL; PUTS("CHARLITERAL"); break; case '"': state = STRINGLITERAL; PUTS("STRINGLITERAL"); break; case '/': c1 = getc(Input); switch(c1) { case '/': state = CC_COMMENT; break; case '*': state = C_COMMENT; break; case EOF: break; default: PUTCHAR(c); ungetc(c1, Input); break; } break; default: PUTCHAR(c); break; } break; case C_COMMENT: /* K&R C comment */ if (c == '\n') { PUTCHAR(c); } else if (c == '*') { c1 = getc(Input); if (c1 == '/') { state = NORMAL; } else { ungetc(c1, Input); } } break; case CPP: switch(c) { case '\n': PUTCHAR(c); state = NORMAL; break; case '\\': c1 = getc(Input); if (c1 == '\n') { PUTCHAR(c1); if (Cppflag) PUTS("cpp"); } break; } break; case CC_COMMENT: /* C++ comment */ if (c == '\n') { PUTCHAR(c); state = NORMAL; } break; case STRINGLITERAL: switch(c) { case '\n': PUTCHAR(c); break; case '"': state = NORMAL; break; /* preserve embedded nulines */ case '\\': c1 = getc(Input); if (c1 == '\n') PUTCHAR(c1); break; } break; case CHARLITERAL: switch(c) { case '\n': PUTCHAR(c); break; case '\'': state = NORMAL; break; case '\\': getc(Input); break; } break; } Lastc = c; } while (state != NORMAL || Pipewrite - Piperead < SIZE / 2); return 0; } void decomment_file(char *fname, FILE *f) { int c; extern int Cppflag; Input = f; Cppflag = 1; while ((c = Getchar()) != EOF) { putc(c, stdout); } } int decomment_files(int argc, char *argv[]) { int result = 0; if (argc == 1) { decomment_file("stdin", stdin); } else { while (argc > 1) { FILE *f; if ((f = fopen(argv[1], "r")) == NULL) { result = 2; perror(argv[1]); } else { decomment_file(argv[1], f); fclose(f); } SHIFT(1); } } return result; } void ncss_Ungetc(int c) { if (c == T_NCNULINE) { ncss_Line--; } Ungetc(c); } void ncss_Ungets(char *s) { Ungets(s); } int ncss_Getchar() { int c; static int blankline = 1; if ((c = Getchar()) != EOF) { if (blankline) { if (!ISSPACE(c)) { blankline = 0; } } else { if (c == '\n') { c = T_NCNULINE; blankline = 1; } } } else { blankline = 1; } if (c == T_NCNULINE) ncss_Line++; return c; } void ncss(FILE *in, int *linesp, int *nclinesp) { int c; int lines = 0; int nclines = 0; int boline = 1; while ((c = Getchar()) != EOF) { if (c == '\n') { lines++; boline = 1; } else if (boline && !ISSPACE(c)) { boline = 0; nclines++; } } *linesp = lines; *nclinesp = nclines; } void ncss_file(char *fname, FILE *f, int *linesp, int *nclinesp) { extern int Cppflag; int lines, nclines; Input = f; Cppflag = 1; ncss(f, &lines, &nclines); if (!Totalsonly) { if (lines != 0) { int pct_csl = (int)(0.4999999 + 100.0 * (lines - nclines) / lines); printf("%6d%4d%6d%4d%7d %-s\n", lines - nclines, pct_csl, nclines, 100 - pct_csl, lines, fname); } else { printf("%6d n/a%6d n/a%7d %-s\n", lines - nclines, nclines, lines, fname); } } *linesp += lines; *nclinesp += nclines; } int ncss_files(int argc, char *argv[]) { int result = 0; int lines = 0, nclines = 0; int nfiles = argc - 1; if (Verbose) puts(" CSL PCT NCSL PCT TOTAL FILENAME"); if (argc == 1) { ncss_file("stdin", stdin, &lines, &nclines); } else { while (argc > 1) { FILE *f; if ((f = fopen(argv[1], "r")) == NULL) { result = 2; perror(argv[1]); } else { ncss_file(argv[1], f, &lines, &nclines); fclose(f); } SHIFT(1); } } if (Totals) { if (lines != 0) { int pct_csl = (int)(0.4999999 + 100.0 * (lines - nclines) / lines); printf("%6d%4d%6d%4d%7d (total files: %d)\n", lines - nclines, pct_csl, nclines, 100 - pct_csl, lines, nfiles); } else { printf("%6d n/a%6d n/a%7d (total files: %d)\n", lines - nclines, nclines, lines, nfiles); } } return result; } pmccabe/test016.ref0000644000000000000000000000107011427042455011244 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 5 1 test016(5): Foo::Foo 1 1 1 10 1 test016(10): Foo::after_potential_parsing_hang 2 2 3 n/a 12 Total CSL PCT NCSL PCT TOTAL FILENAME 4 33 8 67 12 test016 4 33 8 67 12 (total files: 1) pmccabe/test0110000644000000000000000000000022207622477726010501 0ustar struct foo * function1(int a) { return 1; } struct foo function2(int a) { return 1; } struct foo & function3(int a) { return 1; } pmccabe/dmain.h0000644000000000000000000000070207622477726010621 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ /* $Id: dmain.h,v 1.8 2001/01/26 23:00:36 bame Exp $ */ #define EOINPUT 999 #define SIZE (1024 * 8) extern short Pipe[SIZE]; extern short *Piperead; extern short *Pipewrite; extern short *Pipeend; #define PUTCHAR(c) {if (Pipewrite < Pipeend) *Pipewrite++ = (c);} #define PUTS(s) {char *a = s; while (*a != '\0') PUTCHAR(*a++);} extern FILE *Input; extern char Inputfile[1030]; pmccabe/pmccabe.10000644000000000000000000001517507622502427011031 0ustar .TH "pmccabe" 1 12Feb2003 HP .SH NAME pmccabe \- calculate McCabe cyclomatic complexity or non-commented line counts for C and C++ programs .SH SYNOPSIS .B pmccabe [-bCdfFntTvV?] [file(s)] .SH DESCRIPTION .I pmccabe processes the named files, or standard input if none are named. In default mode it calculates statistics including McCabe cyclomatic complexity for each function. The files are expected to be either C (ANSI or K&R) or C++. .TP .B -? Print an informative usage message. .TP .B -v Print column headers .TP .B -V Print .I pmccabe version number .SS De-commenting mode .TP .B -d Intended to help count non-commented source lines via something like: .IP \fCpmccabe -d *.c | grep -v '^[]*$' | wc -l\fR Comments are removed, .I cpp directives are replaced by \fBcpp\fR, string literals are replaced by \fBSTRINGLITERAL\fR, character constants are replaced by \fBCHARLITERAL\fR. The resulting source code is much easier to parse. This is the first step performed by .I pmccabe so that its parser can be simpler. .P None of the other options work sensibly with .BR -d . .SS Line-counting mode .TP .B -n Counts non-commented source lines. The output format is identical to that of the .I anac program except that column headers and totals must be requested if desired. If you want column headers add .BR -v . If you want totals add .BR -t . If all you want is totals add .BR -T . .SS Complexity mode (default) .TP .B -C Custom output format - don't use it. .TP .B -c Report non-commented, non-blank lines per function (and file) instead of the raw number of lines. .B "Note that pre-processor directives are NOT counted." .TP .B -b Output format compatible with compiler error browsing tools which understand "classic" compiler errors. Numerical sorting on this format is possible using: .IP "" \fCsort -n +1 -t%\fR .TP .B -t Print column totals. Note the total number of lines is *NOT* the number of non-commented source lines - it's the same as would be reported by \fC"wc -l"\fR. .TP .B -T Print column totals *ONLY*. .TP .B -f Include per-file totals along with the per-function totals. .TP .B -F Print per-file totals but NOT per-function totals. .SS Parsing .I pmccabe ignores all .I cpp preprocessor directives - calculating the complexity of the appearance of the code rather than the complexity after the preprocessor mangles the code. This is especially important since simple things like .I getchar(3) expand into macros which increase complexity. .SS "Output Format" A line is written to standard output for each function found of the form: .IP .nf \fCModified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 5 6 11 34 27 gettoken.c(35): matchparen\fR .fi .PP Column 1 contains cyclomatic complexity calculated by adding 1 (for the function) to the occurences of .BR for , .BR if , .BR while , .BR switch , .BR && , .BR || , and .BR ? . Unlike "normal" McCabe cyclomatic complexity, each case in a switch statement is not counted as additional complexity. This treatment of switch statements and complexity may be more useful than the "normal" measure for judging maintenance effort and code difficulty. Column 2 is the cyclomatic complexity calculated in the "usual" way with regard to switch statements. Specifically it is calculated as in column 1 but counting each .BR case rather than the .BR switch and may be more useful than column 1 for judging testing effort. Column 3 contains a statement count. It is calculated by adding each occurence of .BR for , " if" , " while" , .BR switch , .BR ? , and semicolon within the function. One possible surprise is that .BR for statements have a minimum statement count of 3. This is realistic since .BR "for(A; B; C){...}" is really shorthand for .BR "A; while (B) { ... C;}" . The number of statements within a file is the sum of the number of statements for each function implemented within that file, plus one for each of those functions (because functions are statements too), plus one for each other file-scoped statement (usually declarations). Column 4 contains the first line number in the function. This is not necessarily the same line on which the function name appears. Column 5 is the number of lines of the function, from the number in column 4 through the line containing the closing curly brace. The final column contains the file name, line number on which the function name occurs, and the name of the function. .SH APPLICATIONS The obvious application of \fIpmccabe\fR is illustrated by the following which gives a list of the "top ten" most complex functions: .IP .nf \fCpmccabe *.c | sort -nr | head -10\fR .fi .PP Many files contain more than one C function and sometimes it would be useful to extract each function separately. \fBmatchparen()\fR (see example output above) can be extracted from gettoken.c by extracting 27 lines starting with line 34. This can form the basis of tools which operate on functions instead of files (e.g., use as a front-end for \fIdiff(1)\fR). .SH DIAGNOSTICS .I pmccabe returns a nonzero exit status if files could not be opened and upon encountering some parsing errors. Error messages to standard error, usually explaining that the parser is confused about something, mimic classic C compiler error messages. .SH WARNINGS .I pmccabe is confused by unmatched curly braces or parentheses which sometimes occur with hasty use of .I cpp directives. In these cases a diagnostic is printed and the complexity results for the files named may be unreliable. Most times the "#ifdef" directives may be modified such that the curly braces match. Note that if .I pmccabe is confused by a .I cpp directive, most pretty printers will be too. In some cases, preprocessing with .IR unifdef (1) may be appropriate. Statement counting could arguably be improved by: counting occurences of the comma operator, multiple assignments, assignments within conditional tests, and logical conjunction. However since there is no crisp statement definition from the language or from people I've queried, statement counting will probably not be improved. If you have a crisp definition I'll be happy to consider it. Templates cause .IR pmccabe 's scanner to exit. It's a shame that .I ctags output isn't provided. .SH AUTHOR Paul Bame .SH "SEE ALSO" .IR codechanges (1), .IR decomment (1), .IR vifn (1), .IR sort (1), .IR diff (1), .IR wc (1), .IR grep (1), .IR unifdef (1), .IR head (1), .IR anac (1) http://parisc-linux.org/~bame/pmccabe/ pmccabe/test006/0000755000000000000000000000000011427053246010547 5ustar pmccabe/test006/NodeArc.H.ref0000644000000000000000000000465107622477726012773 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 31 1 test006/NodeArc.H(31): LabelledNode::~LabelledNode 1 1 1 33 1 test006/NodeArc.H(33): LabelledNode::label 1 1 1 37 1 test006/NodeArc.H(37): LabelledNode::shapeType 1 1 1 39 1 test006/NodeArc.H(39): LabelledNode::borderWidth 1 1 1 40 1 test006/NodeArc.H(40): LabelledNode::borderWidth 1 1 1 42 1 test006/NodeArc.H(42): LabelledNode::xeNode 1 1 1 43 1 test006/NodeArc.H(43): LabelledNode::xeNode 2 2 5 107 10 test006/NodeArc.H(107): LabelledArc::arcContains 2 2 7 118 13 test006/NodeArc.H(118): LabelledArc::labelContains 1 1 3 134 6 test006/NodeArc.H(134): LabelledArc::getLabelOrigin 2 2 5 141 10 test006/NodeArc.H(141): LabelledArc::arrowPoints 1 1 6 152 9 test006/NodeArc.H(152): LabelledArc::arrowBoundingBox 4 4 9 162 12 test006/NodeArc.H(162): LabelledArc::arcBoundingBox 2 2 5 179 9 test006/NodeArc.H(179): LabelledArc::drawArrow 1 1 1 200 1 test006/NodeArc.H(200): LabelledArc::owner 1 1 1 202 1 test006/NodeArc.H(202): LabelledArc::getLabel 1 1 1 205 1 test006/NodeArc.H(205): LabelledArc::getLabelColor 1 1 1 208 1 test006/NodeArc.H(208): LabelledArc::getLabelVisible 1 1 3 234 1 test006/NodeArc.H(234): SiblingList::SiblingList 1 1 1 235 1 test006/NodeArc.H(235): SiblingList::~SiblingList 1 1 1 237 1 test006/NodeArc.H(237): SiblingList::count 1 1 1 238 1 test006/NodeArc.H(238): SiblingList::max 3 3 8 244 11 test006/NodeArc.H(244): SiblingList::isSibling 5 5 18 279 28 test006/NodeArc.H(279): RankedArc::arrowPoints 2 2 2 308 3 test006/NodeArc.H(308): RankedArc::computeRank 2 2 2 312 1 test006/NodeArc.H(312): RankedArc::selfish 8 8 28 314 52 test006/NodeArc.H(314): RankedArc::arcContains 4 4 9 369 15 test006/NodeArc.H(369): RankedArc::getLabelOrigin 6 6 27 385 40 test006/NodeArc.H(385): RankedArc::arcBoundingBox 3 3 8 426 14 test006/NodeArc.H(426): RankedArc::drawArc 10 10 27 441 43 test006/NodeArc.H(441): RankedArc::drawRankedArc 6 6 21 485 36 test006/NodeArc.H(485): RankedArc::drawArrow 2 2 3 526 7 test006/NodeArc.H(526): RankedArc::~RankedArc 80 80 223 n/a 539 Total CSL PCT NCSL PCT TOTAL FILENAME 99 18 440 82 539 test006/NodeArc.H 99 18 440 82 539 (total files: 1) pmccabe/test006/Handler.H0000644000000000000000000004544407622477726012267 0ustar /************************************************************************\ classes used by GraphHandler \************************************************************************/ class ActionHandler; /* public IlvManagerViewInteractor */ class MotionHandler; /* public ActionHandler */ class Selector; /* public MotionHandler */ class SweepSelector; /* public Selector */ class SubgraphSelector; /* public Selector */ class ArcHandler; /* public MotionHandler */ class ArcMaker; /* public ArcHandler */ class ArcChanger; /* public ArcHandler */ class NodeMaker; /* public MotionHandler */ class ItemMover; /* public ActionHandler */ class NodeMover; /* public ItemMover */ class SelectionMover; /* public ItemMover */ class MenuHandler; /* public ActionHandler */ /************************************************************************\ GraphHandler declaration and implementation \************************************************************************/ #define GraphHandlerParent IlvManagerViewInteractor #define GraphHandlerParentPtr IlvManagerViewInteractor* class GraphHandler: public GraphHandlerParent { protected: IlvGraphic* _target; SweepSelector* _sweepSelector; SubgraphSelector* _subgraphSelector; Selector* _toggleSelector; Selector* _selector; NodeMover* _nodeMover; SelectionMover* _selectionMover; ArcMaker* _arcMaker; ArcChanger* _arcChanger; NodeMaker* _nodeMaker; MenuHandler* _menuHandler; public: GraphHandler(GrapherPtr graph, GraphViewPtr view); ~GraphHandler(); virtual void handleEvent(IlvEvent& event); virtual void doIt(IlvGraphic* graphic,const IlvPoint&); }; #define ActionHandlerParent IlvManagerViewInteractor #define ActionHandlerParentPtr IlvManagerViewInteractor* class ActionHandler: public ActionHandlerParent { protected: GraphHandler* _caller; IlvGraphic* _target; void returnControl() { if (_caller) { getManager()->setInteractor(_caller, getView()); } else { getManager()->removeInteractor(getView()); } } ActionHandler(GraphHandler* caller, GrapherPtr manager, IlvView* view) : ActionHandlerParent(manager, view), _caller(caller), _target(nil) { } public: void target(IlvGraphic* t) { _target = t; } IlvGraphic* target() { return _target; } IlvBoolean targetted() { return (_target) ? IlvTrue : IlvFalse; } virtual void handleEvent(IlvEvent& event); virtual void init() { ActionHandlerParent::init(); target(nil); } void takeCharge(IlvEvent& event, IlvGraphic* under = nil) { getManager()->setInteractor(this); target(under); handleEvent(event); } void abort() { ActionHandlerParent::abort(); target(nil); } }; #define MotionHandlerParent ActionHandler #define MotionHandlerParentPtr ActionHandler* class MotionHandler: public MotionHandlerParent { protected: // for rubber-banding IlvPoint _first; IlvPoint _current; virtual void initializeData(IlvEvent& event) { _first.move(event.x(), event.y()); } virtual void updateData(IlvEvent& event, IlvView*, IlvManager*) { _current.move(event.x(), event.y()); } virtual void startMotion(IlvEvent& event) { initializeData(event); drawGhost(); updateMotion(event); } virtual void updateMotion(IlvEvent& event) { drawGhost(); updateData(event, getView(), getManager()); ensureVisible(IlvPoint(event.x(), event.y())); drawGhost(); } virtual void endMotion(IlvEvent& event) { updateData(event, getView(), getManager()); drawGhost(); doIt(); returnControl(); } virtual void drawGhost() { } virtual void doIt() { } MotionHandler(GraphHandler* caller, GrapherPtr manager, IlvView* view) : MotionHandlerParent(caller, manager, view) { } public: virtual IlvBoolean isInitialEvent(IlvEvent&) { return IlvTrue; } virtual IlvBoolean isOkInitialTarget(IlvGraphic*) { return IlvTrue; } virtual IlvBoolean isOkFinalTarget(IlvGraphic*) { return IlvTrue; } virtual void handleEvent(IlvEvent& event); }; #define ArcHandlerParent MotionHandler #define ArcHandlerParentPtr MotionHandler* class ArcHandler: public ArcHandlerParent { protected: IlvCursor* originalCursor; IlvCursor* initialTargetCursor; IlvCursor* noTargetCursor; IlvCursor* finalTargetCursor; void indicateInitialTarget() { IlvDisplay* display = getView()->getDisplay(); originalCursor = display->defaultCursor(); display->setCursor(getView(), initialTargetCursor); // setCursor(originalCursor); } void indicateNoTarget() { getView()->getDisplay()->setCursor(getView(), noTargetCursor); // setCursor(originalCursor); } void indicateFinalTarget() { getView()->getDisplay()->setCursor(getView(), finalTargetCursor); // setCursor(originalCursor); } void indicatePreviousCursor() { getView()->getDisplay()->setCursor(getView(), originalCursor); } virtual void drawGhost() { if ((_current.x() != _first.x()) || (_current.y() != _first.y())) { IlvPoint tf = _first; IlvTransformer* t = getTransformer(); if (t) { t->apply(tf); } getManager()->getDisplay()->drawLine(getView(), getManager()->getPalette(), tf, _current); } } virtual IlvBoolean isInitialEvent(IlvEvent& event) { return (IlvBoolean) (event.modifiers() & IlvCtrlModifier); } virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (t) ? IlvTrue : IlvFalse; } virtual IlvBoolean isOkFinalTarget(IlvGraphic* t) { return (t) ? IlvTrue : IlvFalse; } void initCursors(); void deleteCursors(); /* protected constructor... cannot instantiate one of these */ ArcHandler(GraphHandler* caller, GrapherPtr manager, IlvView* view) : ArcHandlerParent(caller, manager, view) { initCursors(); } ~ArcHandler() { deleteCursors(); } public: }; #define ArcMakerParent ArcHandler #define ArcMakerParentPtr ArcHandler* class ArcMaker: public ArcMakerParent { protected: IlvBoolean exitedTarget; IlvGraphic* finalTarget; virtual void initializeData(IlvEvent& event) { IlvRect bbox; target()->boundingBox(bbox); _first.move(bbox.centerx(), bbox.centery()); _current.move(event.x(), event.y()); exitedTarget = IlvFalse; finalTarget = nil; } virtual void startMotion(IlvEvent& event) { if (!targetted()) { returnControl(); } else { initializeData(event); drawGhost(); indicateInitialTarget(); updateMotion(event); } } virtual void updateMotion(IlvEvent& event) { drawGhost(); IlvPoint p(event.x(), event.y()); IlvManager* mgr = getManager(); IlvView* view = getView(); updateData(event, view, mgr); if (!exitedTarget) { if (mgr->lastContains(p, view) != target()) { exitedTarget = IlvTrue; } } if (exitedTarget) { IlvGraphic* newTarget = mgr->lastContains(p, view); if (finalTarget) { if (newTarget != finalTarget) { if (isOkFinalTarget(newTarget)) { finalTarget = newTarget; } else { finalTarget = nil; } } } else { // no previous final target if (isOkFinalTarget(newTarget)) { finalTarget = newTarget; } } } if (finalTarget) { indicateFinalTarget(); } else if (exitedTarget) { indicateNoTarget(); } // else leave as it was... ensureVisible(IlvPoint(event.x(), event.y())); drawGhost(); } virtual void endMotion(IlvEvent& event) { updateData(event, getView(), getManager()); indicatePreviousCursor(); drawGhost(); if (targetted() && exitedTarget && (finalTarget != nil)) { doIt(); } returnControl(); } virtual void doIt() { XeNodePtr tail = ((LabelledNodePtr) target())->xeNode(); XeNodePtr head = ((LabelledNodePtr) finalTarget)->xeNode(); XeGraphPtr graph = ((GrapherPtr)getManager())->xegraph(); // This will need to be replaced with a call to XeGraph::notify(ArcCreate ) XeArcPtr arc = new XeArc(head, tail, "New Arc", True); } virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (t != nil) && ((GrapherPtr)getManager())->isNode(t); } virtual IlvBoolean isOkFinalTarget(IlvGraphic* t) { return isOkInitialTarget(t); } public: ArcMaker(GraphHandler* caller, GrapherPtr manager, IlvView* view) : ArcMakerParent(caller, manager, view) { } }; #define ArcChangerParent ArcHandler #define ArcChangerParentPtr ArcHandler* class ArcChanger: public ArcChangerParent { protected: IlvGraphic* finalTarget; virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (t != nil) && ((GrapherPtr)getManager())->isLink(t); } virtual IlvBoolean isOkFinalTarget(IlvGraphic* t) { return (t != nil) && ((GrapherPtr)getManager())->isNode(t); } virtual void initializeData(IlvEvent& event) { // decide which end was the initial target. For now, // only allow change of head IlvLinkImage* arc = (IlvLinkImage*) target(); IlvGraphic* node = arc->getFrom(); target(node); IlvRect bbox; node->boundingBox(bbox); _first.move(bbox.centerx(), bbox.centery()); _current.move(event.x(), event.y()); finalTarget = nil; } virtual void startMotion(IlvEvent& event) { if (!targetted()) { returnControl(); } else { initializeData(event); drawGhost(); // this will change to indicate appropriate target. indicateNoTarget(); updateMotion(event); } } virtual void updateMotion(IlvEvent& event) { drawGhost(); IlvPoint p(event.x(), event.y()); IlvManager* mgr = getManager(); IlvView* view = getView(); updateData(event, view, mgr); IlvGraphic* newTarget = mgr->lastContains(p, view); if (finalTarget) { if (newTarget != finalTarget) { if (isOkFinalTarget(newTarget)) { finalTarget = newTarget; } else { finalTarget = nil; } } } else { // no previous final target if (isOkFinalTarget(newTarget)) { finalTarget = newTarget; } } if (finalTarget) { indicateFinalTarget(); } else { indicateNoTarget(); } ensureVisible(IlvPoint(event.x(), event.y())); drawGhost(); } virtual void endMotion(IlvEvent& event) { updateData(event, getView(), getManager()); indicatePreviousCursor(); drawGhost(); if (targetted() && (finalTarget != nil)) { doIt(); } returnControl(); } virtual void doIt(); public: ArcChanger(GraphHandler* caller, GrapherPtr manager, IlvView* view) : ArcChangerParent(caller, manager, view) { } }; #define NodeMakerParent MotionHandler #define NodeMakerParentPtr MotionHandler* class NodeMaker: public NodeMakerParent { protected: IlvRect _xor_rectangle; virtual void drawGhost() { if (_xor_rectangle.w()) { getManager()->getDisplay()->drawRectangle(getView(), getManager()->getPalette(), _xor_rectangle); } } virtual IlvBoolean isInitialEvent(IlvEvent& event) { return (IlvBoolean) (event.modifiers() & IlvCtrlModifier); } virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (t) ? IlvFalse : IlvTrue; } virtual void initializeData(IlvEvent& event) { _xor_rectangle.move(event.x(), event.y()); _xor_rectangle.resize(100, 40); } virtual void updateData(IlvEvent& event, IlvView* view, IlvManager* mgr) { NodeMakerParent::updateData(event, view, mgr); _xor_rectangle.move(event.x(), event.y()); } virtual void doIt(); public: NodeMaker(GraphHandler* caller, GrapherPtr manager, IlvView* view) : NodeMakerParent(caller, manager, view) { } }; const int ObjectLayer = 0; const int HighlightLayer = 1; typedef enum { NewSelection, AddSelection, ToggleSelection } SelectionType; #define SelectorParent MotionHandler #define SelectorParentPtr MotionHandler* class Selector: public SelectorParent { protected: // used to determine actions in various modes SelectionType _type; IlvPoint _p; IlvPoint _tp; IlvRegion _region; // for manipulating an individual object IlvBoolean _wasSelected; // for outlining individual graphical objects Outliner* _outliner; void deselect() { getManager()->deSelectAll(); } virtual void updateData(IlvEvent& event, IlvView* view, IlvManager* mgr) { SelectorParent::updateData(event, view, mgr); _p.move(event.x(), event.y()); _tp = _p; IlvTransformer* xform = getTransformer(); if (xform) { xform->apply(_tp); } } virtual IlvBoolean isInitialEvent(IlvEvent& event) { return (IlvBoolean) ((!event.modifiers()) || (event.modifiers() & IlvCtrlModifier)); } virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (IlvBoolean)(t != nil); // && ((GrapherPtr) getManager())->isNode(target())); } public: Selector(GraphHandler* caller, GrapherPtr manager, IlvView* view) : SelectorParent(caller, manager, view) , _type(NewSelection) , _wasSelected(IlvFalse) , _outliner(nil) { } virtual void init(); virtual void startMotion(IlvEvent& event); virtual void updateMotion(IlvEvent& event); virtual void endMotion(IlvEvent& event); }; #define SweepSelectorParent Selector #define SweepSelectorParentPtr Selector* class SweepSelector: public SweepSelectorParent { protected: // for sweeping out rectangles for selection IlvRect _xor_rectangle; IlvPos _firstx; IlvPos _firsty; void updateData(IlvEvent& event, IlvView* view, IlvManager* mgr) { SweepSelectorParent::updateData(event, view, mgr); _xor_rectangle.move(IlvMin(_firstx, event.x()), IlvMin(_firsty, event.y())); _xor_rectangle.resize((IlvDim)(IlvMax(_firstx, event.x()) - _xor_rectangle.x()), (IlvDim)(IlvMax(_firsty, event.y()) - _xor_rectangle.y())); } virtual void startMotion(IlvEvent& event) { if (targetted()) { returnControl(); } else { _firstx = event.x(); _firsty = event.y(); _xor_rectangle.w(0); #if 0 deselect(); #endif updateMotion(event); } } virtual void updateMotion(IlvEvent& event) { if (_xor_rectangle.w()) drawGhost(); updateData(event, getView(), getManager()); ensureVisible(IlvPoint(event.x(), event.y())); drawGhost(); } virtual void endMotion(IlvEvent& event) { deselect(); updateData(event, getView(), getManager()); if (_xor_rectangle.w()) { drawGhost(); doIt(); _xor_rectangle.w(0); } returnControl(); } virtual void doIt(); virtual void drawGhost() { if (_xor_rectangle.w()) { getManager()->getDisplay()->drawRectangle(getView(), getManager()->getPalette(), _xor_rectangle); } } IlvBoolean isInitialEvent(IlvEvent& event) { return (IlvBoolean) !event.modifiers(); } IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (IlvBoolean)(t == nil); } public: SweepSelector(GraphHandler* caller, GrapherPtr manager, IlvView* view) : SweepSelectorParent(caller, manager, view) { } }; #define SubgraphSelectorParent Selector #define SubgraphSelectorParentPtr Selector* class SubgraphSelector: public SubgraphSelectorParent { protected: // for selecting subgraph -- _target holds topmost node... IlvUInt _nSubgraphNodes; LabelledNodePtr* _subgraph; Outliner** _subgraphOutliners; virtual void startMotion(IlvEvent& event); virtual void updateMotion(IlvEvent& event); virtual void endMotion(IlvEvent& event); IlvBoolean isInitialEvent(IlvEvent& event) { return (IlvBoolean) (event.modifiers() & IlvShiftModifier); } IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (IlvBoolean)(t && ((GrapherPtr) getManager())->isNode(target())); } public: SubgraphSelector(GraphHandler* caller, GrapherPtr manager, IlvView* view) : SubgraphSelectorParent(caller, manager, view) { } }; #define ItemMoverParent ActionHandler #define ItemMoverParentPtr ActionHandler* class ItemMover: public ItemMoverParent { protected: virtual void startMove(IlvEvent&) { } virtual void updateMove(IlvEvent&) { } virtual void endMove(IlvEvent&) { } virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (t != nil) && ((GrapherPtr) getManager())->isNode(t); } public: ItemMover(GraphHandler* caller, GrapherPtr manager, IlvView* view) : ItemMoverParent(caller, manager, view) { } void handleEvent(IlvEvent& event); }; #define NodeMoverParent ItemMover #define NodeMoverParentPtr ItemMover* class NodeMover: public NodeMoverParent { protected: IlvPos _deltax, _deltay; void startMove(IlvEvent& event) { IlvRect bbox; target()->boundingBox(bbox, getTransformer()); _deltax = event.x() - bbox.x(); _deltay = event.y() - bbox.y(); } virtual void updateMove(IlvEvent& event) { IlvRect bbox; target()->boundingBox(bbox, getTransformer()); IlvPoint newOrigin(event.x() - _deltax, event.y() - _deltay); if(getTransformer()) getTransformer()->inverse(newOrigin); target()->boundingBox(bbox); IlvDeltaPoint dp((IlvDeltaPos)(newOrigin.x()-bbox.x()), (IlvDeltaPos)(newOrigin.y()-bbox.y())); doIt(target(), dp); } virtual void endMove(IlvEvent&) { target(nil); } virtual void doIt(IlvGraphic* graphic,const IlvDeltaPoint& p); public: NodeMover(GraphHandler* caller, GrapherPtr manager, IlvView* view) : NodeMoverParent(caller, manager, view) { } }; #define SelectionMoverParent NodeMover #define SelectionMoverParentPtr NodeMover* class SelectionMover: public SelectionMoverParent { protected: virtual IlvBoolean isOkInitialTarget(IlvGraphic* t) { return (IlvBoolean) (t && getManager()->isSelected(t) && ((GrapherPtr)getManager())->isNode(t)); } virtual void doIt(IlvGraphic* graphic, const IlvDeltaPoint& p); public: SelectionMover(GraphHandler* caller, GrapherPtr manager, IlvView* view) : SelectionMoverParent(caller, manager, view) { } }; #define MenuHandlerParent ActionHandler #define MenuHandlerParentPtr ActionHandler* class MenuHandler : public MenuHandlerParent { public: MenuHandler(GraphHandler* caller, GrapherPtr manager, IlvView* view) : MenuHandlerParent(caller, manager, view) { } void handleEvent(IlvEvent& event); }; extern void PopupMenu(XegPopupMenuPtr menu, Widget w, IlvEvent* event); pmccabe/test006/Grapher.H0000644000000000000000000000150007622477726012263 0ustar /************************************************************************\ Grapher declaration \************************************************************************/ #define GrapherParent IlvGrapher #define GrapherParentPtr IlvGrapher* class Grapher: public GrapherParent { protected: XeGraphPtr xeg; static IlvDrawSelection* select(IlvManager* mgr, IlvGraphic* object); public: Grapher(XeGraphPtr g, IlvDisplay* display, int layers = 2, IlvBoolean useacc = IlvTrue, unsigned short maxInList = IlvMaxObjectsInList, unsigned short maxInNode = IlvMaxObjectsInList) : GrapherParent(display, layers, useacc, maxInList, maxInNode) { xeg = g; setMakeSelection(Grapher::select); } ~Grapher() { } XeGraphPtr xegraph() { return xeg; } }; pmccabe/test006/NodeArc.H0000644000000000000000000003347707622477726012230 0ustar /************************************************************************\ LabelledNode declaration \************************************************************************/ class Shaper; #define LabelledNodeParent IlvListLabel #define LabelledNodeParentPtr IlvListLabel* class LabelledNode: public LabelledNodeParent { private: protected: char* label_; IlvColor* border_; IlvShort bwidth_; XeNodePtr xeNode_; ShapeType shapeType_; Shaper* shaper_; virtual void drawShape(IlvDisplay* dpy, IlvPort* dst, IlvPalette* palette, IlvTransformer* t, IlvRect& r) ; virtual void baseBoundingBox(IlvRect& r, IlvTransformer* t=0); public: LabelledNode(XeNodePtr xenode, IlvDisplay* dpy, const IlvPoint& p, char* lbl , IlvShort bwidth, IlvPalette* palette = nil); ~LabelledNode() { ; } void label(char*); char* label() { return (label_); } void borderColor(char*); void shape(ShapeType type); ShapeType shapeType() { return shapeType_; } IlvShort borderWidth() { return bwidth_; } void borderWidth(IlvShort w) { bwidth_ = w; } XeNodePtr xeNode() { return xeNode_; } void xeNode(XeNodePtr n) { xeNode_ = n; } virtual void draw(IlvPort* dst, IlvTransformer* t, IlvRegion* rect=0); virtual void boundingBox(IlvRect& r, IlvTransformer* t=0); virtual IlvBoolean contains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer* t); virtual void computeRegion(IlvRegion& r, IlvTransformer* t=0); static LabelledNode* makeShapedNode(XeNodePtr node, IlvDisplay* dpy, const ShapeType type, const IlvPoint& p, char* label, IlvShort bwidth); DeclareTypeInfo(); }; typedef enum { FixedPosition = 0x0, RelativePosition = 0x1 } ArcEndType; /************************************************************************\ LabelledArc declaration and implementation \************************************************************************/ typedef IlvLinkImage ArcRootClass; class TextList; #define RECURSIVE_BEZIER_ARCS 1 // IlvDisplay::drawArrow(dst, transform, start, end, atPos) requires // atPos in the range [0.0,1.0]. 0.0 means draw the arrow at the // beginning of line, 1.0 means draw at end... const float ArrowAtStart = 0.0; const float ArrowAtEnd = 1.0; const int NodeBorderAllowance = 4; #define LabelledArcParent IlvLinkImage #define LabelledArcParentPtr IlvLinkImage* class LabelledArc: public LabelledArcParent { protected: XeArcPtr arc; char* label; Boolean labelVisible; char* labelColorString; IlvColor* labelColor; TextList* tlist; #if RECURSIVE_BEZIER_ARCS IlvPoint _points[7]; IlvShort _nPoints; IlvPoint _labelOrigin; #else IlvPoint _points[4]; IlvInt _nPoints; IlvPoint _labelOrigin; #endif IlvBoolean arrowContains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer*t=0); virtual IlvBoolean arcContains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer*t=0) { IlvBoolean isIn; isIn = IlvPointInLine(p, _points[0], _points[1]); if (!isIn) { isIn = arrowContains(p, tp, t); } return isIn; } virtual IlvBoolean labelContains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer*t=0) { IlvRect r; labelBoundingBox(r, t); IlvBoolean isIn; if (t) { isIn = r.contains(tp); } else { isIn = r.contains(p); } return isIn; } // calculate the origination point for the label, using the // indicated transformation virtual void getLabelOrigin(IlvPoint& origin, IlvTransformer* t=0) { IlvRect r; arcBoundingBox(r, t); origin.move(r.centerx(), r.centery()); } virtual void arrowPoints(IlvPoint* points, IlvTransformer* t=0) { // This should really calculate the points then apply the transformer... IlvPoint from = _points[0], to = _points[1]; if (t) { t->apply(from); t->apply(to); } IlvComputeArrow(from, to, ArrowAtEnd, points); } virtual void arrowBoundingBox(IlvRect& r, IlvTransformer* t=0) { IlvPoint pts[3]; arrowPoints(pts, t); r.resize(0,0); r.move(pts[0]); r.add(pts[1]); r.add(pts[2]); } virtual void arcBoundingBox(IlvRect& r, IlvTransformer* t=0) { r.move(_points[0]); r.resize(0,0); r.add(_points[1]); if (t) t->apply(r); IlvRect arrowBox; arrowBoundingBox(arrowBox, t); if (arrowBox.w() != 0 && arrowBox.h() != 0) { r.add(arrowBox); } } // find the label's origin relative to the non-transformed bounding // box, then calculate the label's bounding box using the // indicated transformation... virtual void labelBoundingBox(IlvRect& r, IlvTransformer* t=0); virtual void drawArrow(IlvPort* dst, IlvTransformer* t=0, IlvRegion* = 0) { IlvPoint start = _points[0], end = _points[1]; if (t) { t->apply(start); t->apply(end); } getDisplay()->drawArrow(dst, getPalette(), start, end, ArrowAtEnd); } virtual void drawArc(IlvPort* dst, IlvTransformer* t=0, IlvRegion* rect=0); virtual void drawLabel(IlvPort* dst, IlvTransformer* t, IlvRegion* clip=0); virtual void computePoints(IlvGraphic* f, IlvGraphic* t); public: LabelledArc(XeArcPtr owner, IlvDisplay* dpy, char* lbl, UIPtr tail, UIPtr head, Boolean showLabel = True); ~LabelledArc(); XeArcPtr owner() { return arc; } char* getLabel() { return label; } void setLabel(char* s); char* getLabelColor() { return labelColorString; } void setLabelColor(char* c); Boolean getLabelVisible() { return labelVisible; } void setLabelVisible(Boolean v); virtual IlvBoolean contains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer*t =0); virtual void draw(IlvPort* dst, IlvTransformer* t=0, IlvRegion* rect=0); virtual void boundingBox(IlvRect&, IlvTransformer*t =0); virtual void computeRegion(IlvRegion& r, IlvTransformer* t); DeclareTypeInfo(); }; /************************************************************************\ sibling computation code -- perhaps this should be a nested class of arcs \************************************************************************/ class SiblingList { protected: XeArcPtr* arcs; int nSlots; int nArcs; void listAppend(XeArcPtr sib); void listRemove(XeArcPtr sib); public: SiblingList() { nSlots = 0; nArcs = 0; arcs = nil; } ~SiblingList() { delete arcs; } int count() { return nArcs; } int max() { return nSlots; } void insert(XeArcPtr sib); void remove(XeArcPtr sib); int rank(XeArcPtr); IlvBoolean isSibling(XeArcPtr sib) { IlvBoolean isSib = IlvFalse; for(int i = 0; i < nArcs; i++) { if (arcs[i] == sib) { isSib = IlvTrue; break; } } return isSib; } }; #if RECURSIVE_BEZIER_ARCS const IlvFloat RankedArcArrowPosition = ArrowAtEnd; #else const IlvFloat RankedArcArrowPosition = 0.6; #endif #define RankedArcParent LabelledArc #define RankedArcParentPtr LabelledArc* class RankedArc: public RankedArcParent { protected: IlvGraphic* _selfNode; #if !RECURSIVE_BEZIER_ARCS EllipseInfo* _eInfo; #endif int currentRank; // Compute the control points for our curve based on rank and // current position of head and tail of arc virtual void computePoints(IlvGraphic* f, IlvGraphic* t); virtual void arrowPoints(IlvPoint* points, IlvTransformer* t=0) { // This should really calculate the points then apply the transformer... IlvPoint from, to; IlvFloat arrowPos = ArrowAtEnd; if (currentRank == 0 && !selfish()) { RankedArcParent::arrowPoints(points, t); return; } if (selfish()) { #if RECURSIVE_BEZIER_ARCS arrowPos = RankedArcArrowPosition; from = _points[5]; to = _points[6]; #else arrowPos = RankedArcArrowPosition; from = _eInfo->startArrow(); to = _eInfo->endArrow(); #endif } else { from = _points[2]; to = _points[3]; } if (t) { t->apply(from); t->apply(to); } IlvComputeArrow(from, to, arrowPos, points); } int computeRank() { return owner()->siblings() ? owner()->siblings()->rank(owner()): 0; } IlvBoolean selfish() { return _selfNode ? IlvTrue : IlvFalse; } virtual IlvBoolean arcContains(const IlvPoint& p, const IlvPoint& tp, IlvTransformer*t=0) { IlvBoolean isIn = IlvFalse; currentRank = computeRank(); IlvGraphic* tail = getFrom(); IlvGraphic* head = getTo(); computePoints(tail, head); if (currentRank == 0 && !selfish()) { isIn = RankedArcParent::arcContains(p, tp, t); } else { if (t) { #if RECURSIVE_BEZIER_ARCS IlvPoint points[8]; #else IlvPoint points[4]; #endif for (int i = 0; i < _nPoints; i++) { points[i] = _points[i]; t->apply(points[i]); } // check the "transformed point" supplied by Views manager... #if RECURSIVE_BEZIER_ARCS isIn = IlvPointInSpline(tp, _nPoints, points); #else if (selfish()) { IlvRect r = _eInfo->rect(); t->apply(r); isIn = PointOnArc(tp, r, _eInfo->startAngle(), _eInfo->deltaAngle(), /* tolerance */ 2); } else { isIn = IlvPointInSpline(tp, _nPoints, points); } #endif } else { #if RECURSIVE_BEZIER_ARCS isIn = IlvPointInSpline(p, _nPoints, _points); #else if (selfish()) { isIn = PointOnArc(p, _eInfo->rect(), _eInfo->startAngle(), _eInfo->deltaAngle(), /* tolerance */ 2); } else { isIn = IlvPointInSpline(p, _nPoints, _points); } #endif } if (!isIn) { isIn = arrowContains(p, tp, t); } } return isIn; } // calculate the origination point for the label, using the // indicated transformation virtual void getLabelOrigin(IlvPoint& origin, IlvTransformer* t=0) { currentRank = computeRank(); IlvGraphic* tail = getFrom(); IlvGraphic* head = getTo(); computePoints(tail, head); if (currentRank == 0 && !selfish()) { RankedArcParent::getLabelOrigin(origin, t); } else { origin = _labelOrigin; if (t) { t->apply(origin); } } } virtual void arcBoundingBox(IlvRect& r, IlvTransformer* t=0) { currentRank = computeRank(); IlvGraphic* tail = getFrom(); IlvGraphic* head = getTo(); computePoints(tail, head); if (currentRank == 0 && !selfish()) { RankedArcParent::arcBoundingBox(r, t); } else { #if RECURSIVE_BEZIER_ARCS r.move(_points[0]); r.resize(0,0); r.add(_points[1]); r.add(_points[2]); r.add(_points[3]); if (selfish()) { // only valid for self arcs... r.add(_points[4]); r.add(_points[5]); r.add(_points[6]); } #else if (selfish()) { IlvComputeArcBBox(_eInfo->rect(), _eInfo->startAngle(), _eInfo->deltaAngle(), r); } else { r.move(_points[0]); r.resize(0,0); r.add(_points[1]); r.add(_points[2]); r.add(_points[3]); } #endif IlvRect arrowBox; arrowBoundingBox(arrowBox, 0); r.add(arrowBox); if (t) t->apply(r); } } virtual void drawArc(IlvPort* dst, IlvTransformer* t=0, IlvRegion* rect=0) { currentRank = computeRank(); IlvGraphic* tail = getFrom(); IlvGraphic* head = getTo(); computePoints(tail, head); if (currentRank == 0 && !selfish()) { RankedArcParent::drawArc(dst, t, rect); } else { // how do we draw the arrow??? drawArrow(dst, t, rect); drawRankedArc(currentRank, dst, t, rect); } } virtual void drawRankedArc(int rank, IlvPort* dst, IlvTransformer* t=0, IlvR egion* rect=0) { #if RECURSIVE_BEZIER_ARCS if (selfish() || rank > 0) { if (!t) { getDisplay()->drawBezier(dst, getPalette(), _nPoints, _points); } else { IlvPoint points[8]; for (int i = 0; i < _nPoints; i++) { points[i] = _points[i]; t->apply(points[i]); } getDisplay()->drawBezier(dst, getPalette(), _nPoints, points); } } else { // shouldn't reach this point... RankedArcParent::drawArc(dst, t, rect); } #else if (selfish()) { IlvRect r = _eInfo->rect(); if (t) t->apply(r); getDisplay()->drawArc(dst, getPalette(), r, (IlvFloat) _eInfo->startAngle(), (IlvFloat) _eInfo->deltaAngle()); } else if (rank > 0) { if (t) { IlvPoint points[4]; for (int i = 0; i < _nPoints; i++) { points[i] = _points[i]; t->apply(points[i]); } getDisplay()->drawBezier(dst, getPalette(), _nPoints, points); } else { getDisplay()->drawBezier(dst, getPalette(), _nPoints, _points); } } else { // shouldn't reach this point... RankedArcParent::drawArc(dst, t, rect); } #endif } virtual void drawArrow(IlvPort* dst, IlvTransformer* t=0, IlvRegion* r=0) { IlvBoolean selfArc = selfish(); if (!selfArc && currentRank == 0) { RankedArcParent::drawArrow(dst, t, r); } else { IlvPoint start, end; IlvFloat arrowPos = ArrowAtEnd; #if RECURSIVE_BEZIER_ARCS if (selfArc) { start = _points[5]; end = _points[6]; arrowPos = RankedArcArrowPosition; } else { start = _points[2]; end = _points[3]; } #else if (selfArc) { start = _eInfo->startArrow(); end = _eInfo->endArrow(); arrowPos = RankedArcArrowPosition; } else { // we use the control points of our spline to determine direction // and "slope" of arrow's center... start = _points[2]; end = _points[3]; } #endif if (t) { t->apply(start); t->apply(end); } getDisplay()->drawArrow(dst, getPalette(), start, end, arrowPos); } } public: RankedArc(XeArcPtr owner, IlvDisplay* dpy, char* lbl, UIPtr tail, UIPtr head, Boolean showLabel = True); ~RankedArc() { _nPoints = 0; #if !RECURSIVE_BEZIER_ARCS if (_selfNode) delete _eInfo; #endif } DeclareTypeInfo(); }; pmccabe/test006/Handler.H.ref0000644000000000000000000001230507622477726013030 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 2 2 3 68 8 test006/Handler.H(68): ActionHandler::returnControl 1 1 3 77 4 test006/Handler.H(77): ActionHandler::ActionHandler 1 1 1 83 1 test006/Handler.H(83): ActionHandler::target 1 1 1 84 1 test006/Handler.H(84): ActionHandler::target 2 2 2 85 1 test006/Handler.H(85): ActionHandler::targetted 1 1 2 89 4 test006/Handler.H(89): ActionHandler::init 1 1 3 94 6 test006/Handler.H(94): ActionHandler::takeCharge 1 1 2 101 4 test006/Handler.H(101): ActionHandler::abort 1 1 1 117 4 test006/Handler.H(117): MotionHandler::initializeData 1 1 1 122 4 test006/Handler.H(122): MotionHandler::updateData 1 1 3 127 5 test006/Handler.H(127): MotionHandler::startMotion 1 1 4 132 6 test006/Handler.H(132): MotionHandler::updateMotion 1 1 4 138 6 test006/Handler.H(138): MotionHandler::endMotion 1 1 0 145 1 test006/Handler.H(145): MotionHandler::drawGhost 1 1 0 146 1 test006/Handler.H(146): MotionHandler::doIt 1 1 1 148 4 test006/Handler.H(148): MotionHandler::MotionHandler 1 1 1 155 1 test006/Handler.H(155): MotionHandler::isInitialEvent 1 1 1 156 1 test006/Handler.H(156): MotionHandler::isOkInitialTarget 1 1 1 157 1 test006/Handler.H(157): MotionHandler::isOkFinalTarget 1 1 3 174 6 test006/Handler.H(174): ArcHandler::indicateInitialTarget 1 1 1 180 4 test006/Handler.H(180): ArcHandler::indicateNoTarget 1 1 1 184 4 test006/Handler.H(184): ArcHandler::indicateFinalTarget 1 1 1 188 3 test006/Handler.H(188): ArcHandler::indicatePreviousCursor 4 4 6 192 15 test006/Handler.H(192): ArcHandler::drawGhost 1 1 1 208 4 test006/Handler.H(208): ArcHandler::isInitialEvent 2 2 2 213 4 test006/Handler.H(213): ArcHandler::isOkInitialTarget 2 2 2 217 4 test006/Handler.H(217): ArcHandler::isOkFinalTarget 1 1 2 227 5 test006/Handler.H(227): ArcHandler::ArcHandler 1 1 1 232 4 test006/Handler.H(232): ArcHandler::~ArcHandler 1 1 6 250 10 test006/Handler.H(250): ArcMaker::initializeData 2 2 6 260 10 test006/Handler.H(260): ArcMaker::startMotion 10 10 23 271 37 test006/Handler.H(271): ArcMaker::updateMotion 4 4 6 309 11 test006/Handler.H(309): ArcMaker::endMotion 1 1 4 321 10 test006/Handler.H(321): ArcMaker::doIt 2 2 1 332 4 test006/Handler.H(332): ArcMaker::isOkInitialTarget 1 1 1 336 4 test006/Handler.H(336): ArcMaker::isOkFinalTarget 1 1 1 342 4 test006/Handler.H(342): ArcMaker::ArcMaker 2 2 1 356 4 test006/Handler.H(356): ArcChanger::isOkInitialTarget 2 2 1 360 4 test006/Handler.H(360): ArcChanger::isOkFinalTarget 1 1 8 365 12 test006/Handler.H(365): ArcChanger::initializeData 2 2 6 378 12 test006/Handler.H(378): ArcChanger::startMotion 6 6 18 391 30 test006/Handler.H(391): ArcChanger::updateMotion 3 3 6 422 11 test006/Handler.H(422): ArcChanger::endMotion 1 1 1 436 4 test006/Handler.H(436): ArcChanger::ArcChanger 2 2 2 451 8 test006/Handler.H(451): NodeMaker::drawGhost 1 1 1 459 4 test006/Handler.H(459): NodeMaker::isInitialEvent 2 2 2 464 4 test006/Handler.H(464): NodeMaker::isOkInitialTarget 1 1 2 469 5 test006/Handler.H(469): NodeMaker::initializeData 1 1 2 474 5 test006/Handler.H(474): NodeMaker::updateData 1 1 1 482 4 test006/Handler.H(482): NodeMaker::NodeMaker 1 1 1 515 3 test006/Handler.H(515): Selector::deselect 2 2 6 519 10 test006/Handler.H(519): Selector::updateData 2 2 1 530 5 test006/Handler.H(530): Selector::isInitialEvent 1 1 1 536 5 test006/Handler.H(536): Selector::isOkInitialTarget 1 1 4 543 7 test006/Handler.H(543): Selector::Selector 1 1 3 570 10 test006/Handler.H(570): SweepSelector::updateData 2 2 7 581 13 test006/Handler.H(581): SweepSelector::startMotion 2 2 5 595 7 test006/Handler.H(595): SweepSelector::updateMotion 2 2 7 603 10 test006/Handler.H(603): SweepSelector::endMotion 2 2 2 616 8 test006/Handler.H(616): SweepSelector::drawGhost 1 1 1 625 4 test006/Handler.H(625): SweepSelector::isInitialEvent 1 1 1 630 4 test006/Handler.H(630): SweepSelector::isOkInitialTarget 1 1 1 636 4 test006/Handler.H(636): SweepSelector::SweepSelector 1 1 1 658 4 test006/Handler.H(658): SubgraphSelector::isInitialEvent 2 2 1 663 4 test006/Handler.H(663): SubgraphSelector::isOkInitialTarget 1 1 1 669 4 test006/Handler.H(669): SubgraphSelector::SubgraphSelector 1 1 0 681 1 test006/Handler.H(681): ItemMover::startMove 1 1 0 682 1 test006/Handler.H(682): ItemMover::updateMove 1 1 0 683 1 test006/Handler.H(683): ItemMover::endMove 2 2 1 685 3 test006/Handler.H(685): ItemMover::isOkInitialTarget 1 1 1 689 4 test006/Handler.H(689): ItemMover::ItemMover 1 1 4 706 6 test006/Handler.H(706): NodeMover::startMove 2 2 8 712 11 test006/Handler.H(712): NodeMover::updateMove 1 1 1 723 3 test006/Handler.H(723): NodeMover::endMove 1 1 1 728 4 test006/Handler.H(728): NodeMover::NodeMover 3 3 1 740 4 test006/Handler.H(740): SelectionMover::isOkInitialTarget 1 1 1 746 4 test006/Handler.H(746): SelectionMover::SelectionMover 1 1 1 758 4 test006/Handler.H(758): MenuHandler::MenuHandler 122 122 246 n/a 770 Total CSL PCT NCSL PCT TOTAL FILENAME 151 20 619 80 770 test006/Handler.H 151 20 619 80 770 (total files: 1) pmccabe/test006/Grapher.H.ref0000644000000000000000000000120407622477726013037 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 3 16 11 test006/Grapher.H(16): Grapher::Grapher 1 1 0 27 1 test006/Grapher.H(27): Grapher::~Grapher 1 1 1 29 1 test006/Grapher.H(29): Grapher::xegraph 3 3 5 n/a 32 Total CSL PCT NCSL PCT TOTAL FILENAME 11 34 21 66 32 test006/Grapher.H 11 34 21 66 32 (total files: 1) pmccabe/test0040000644000000000000000000000034507622477726010511 0ustar class T1 { int i; operator long(); class /* unnamed */ { int member(int a) { return a; }; }; class T11 { class T12 { int member(int a, int b) { return a = b; }; } } }; pmccabe/test011.ref0000644000000000000000000000110107622477726011251 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 1 1 1 2 5 test011(3): function1 1 1 1 8 5 test011(9): function2 1 1 1 14 5 test011(15): function3 3 3 6 n/a 18 Total CSL PCT NCSL PCT TOTAL FILENAME 3 17 15 83 18 test011 3 17 15 83 18 (total files: 1) pmccabe/io.c0000644000000000000000000000124507622477726010136 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #include "dmain.h" #include "pmccabe.h" int Line; int Unbuf[256]; int *Unptr = Unbuf; void Ungetc(int c) { if (c == '\n') { Line--; } *Unptr++ = c; } void Ungets(char *s) { int c; char *ptr; ptr = s + strlen(s); do { c = *--ptr; if (!ISSPACE(c)) if (c == '\n') { Line--; } *Unptr++ = c; } while (ptr != s); } int Getchar() { int c; if (Unptr == Unbuf) { if (Piperead >= Pipewrite) decomment(); c = *Piperead++; } else { c = *--Unptr; } if (c == '\n') Line++; return c; } pmccabe/test010.ref0000644000000000000000000000073607622477726011265 0ustar Modified McCabe Cyclomatic Complexity | Traditional McCabe Cyclomatic Complexity | | # Statements in function | | | First line of function | | | | # lines in function | | | | | filename(definition line number):function | | | | | | 0 0 1 n/a 7 Total CSL PCT NCSL PCT TOTAL FILENAME 1 14 6 86 7 test010 1 14 6 86 7 (total files: 1) pmccabe/nmain.c0000644000000000000000000001206710660217316010614 0ustar /* Copyright (c) 2002 Hewlett-Packard under GPL version 2 or later */ #include #if defined MSC6 || defined WIN32 #define MAXPATHLEN 1024 #else #include /* for MAXPATHLEN */ #endif #include #include #include "pmccabe.h" #include "dmain.h" /* $Id: nmain.c,v 1.23 2001/01/26 23:00:37 bame Exp $ */ int Exit = 0; void file(char *fname, FILE *f) { stats_t *filestats; extern int Unbuf[], *Unptr; extern int Pass1; Input = f; if (Pass1) { int c; extern int Cppflag; Cppflag = 1; while ((c = Getchar()) != EOF) { putc(c, stdout); } return; } Unptr = Unbuf; Line = 1; ncss_Line = 0; ZERO(filestats); filestats = stats_push(fname, STATS_FILE); filestats->firstline = 1; while (toplevelstatement(filestats) != EOF) { filestats->nsemicolons++; } filestats->lastline = Line - 1; /* Not 100% sure why I need to subtract 1 here */ filestats->nLines += ncss_Line - 1; if (Files) printstats(filestats); stats_pop(filestats); } void cycoprintstats(stats_t *fs, stats_t *fn) { int basic, cycloswitch, cyclocase; basic = fn->nfor + fn->nwhile + fn->nif + fn->nand + fn->nor + fn->nq; cycloswitch = 1 + basic + fn->nswitch; cyclocase = 1 + basic + fn->ncase; printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\t%s\n", cycloswitch, cyclocase, fn->nstatements, fn->firstline, fn->defline, fn->lastline, fn->lastline - fn->firstline + 1, fs->name, fn->name); } void softbuildprintstats(stats_t *fs, stats_t *fn) { int basic, cycloswitch, cyclocase; basic = fn->nfor + fn->nwhile + fn->nif + fn->nand + fn->nor + fn->nq; cycloswitch = 1 + basic + fn->nswitch; cyclocase = 1 + basic + fn->ncase; printf("\"%s\", line %d: %s%%\t%d\t%d\t%d\t%d\t%d\n", fs->name, fn->defline, fn->name, cycloswitch, cyclocase, fn->nstatements, fn->firstline, fn->lastline - fn->firstline + 1); } static void printname(stats_t *sp) { if (sp != NULL) { printname(sp->prev); switch(sp->type) { case STATS_TOTAL: case STATS_FILE: break; case STATS_FUNCTION: printf("%s", sp->name); break; case STATS_CLASS: if (sp->prev != NULL && sp->prev->type == STATS_FUNCTION) printf("/"); printf("%s::", sp->name); break; case STATS_NAMESPACE: printf("%s::", sp->name); break; } } } void printstats(stats_t *sp) { int basic, cycloswitch, cyclocase; static int t_cswitch = 0; static int t_ccase = 0; static int t_statements = 0; static int t_lines = 0; int snlines; stats_t *fsp; basic = sp->nfor + sp->nwhile + sp->nif + sp->nand + sp->nor + sp->nq; sp->nstatements = basic - sp->nand - sp->nor + sp->nsemicolons; cycloswitch = sp->nfunctions + basic + sp->nswitch; cyclocase = sp->nfunctions + basic + sp->ncase; for (fsp = sp; fsp != NULL && fsp->type != STATS_FILE; fsp = fsp->prev) { } if (Ncssfunction) { snlines = sp->nLines + 1; } else { snlines = sp->lastline - sp->firstline + 1; } switch(sp->type) { case STATS_TOTAL: if (Softbuild) { printf("\"n/a\", line n/a: %s", sp->name); printf("%%\t%d\t%d\t%d\tn/a\t%d\n", cycloswitch, cyclocase, sp->nstatements, snlines); } else if (Cyco) { printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", cycloswitch, cyclocase, sp->nstatements, sp->firstline, sp->defline, sp->lastline, snlines, "Total"); } else { printf("%d\t%d\t%d\tn/a\t%d\t", cycloswitch, cyclocase, sp->nstatements, snlines); printf("Total\n"); } break; case STATS_FILE: assert(fsp != NULL); if (Softbuild) { printf("\"%s\", line 1: n/a", fsp->name); printf("%%\t%d\t%d\t%d\t%d\t%d\n", cycloswitch, cyclocase, sp->nstatements, sp->firstline, snlines); } else if (Cyco) { printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", cycloswitch, cyclocase, sp->nstatements, sp->firstline, sp->defline, sp->lastline, snlines, fsp->name); } else { printf("%d\t%d\t%d\t%d\t%d\t", cycloswitch, cyclocase, sp->nstatements, sp->firstline, snlines); printf("%s\n", fsp->name); } break; case STATS_FUNCTION: assert(fsp != NULL); if (Softbuild) { printf("\"%s\", line %d: ", fsp->name, sp->defline); printname(sp); printf("%%\t%d\t%d\t%d\t%d\t%d\n", cycloswitch, cyclocase, sp->nstatements, sp->firstline, snlines); } else if (Cyco) { printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\t", cycloswitch, cyclocase, sp->nstatements, sp->firstline, sp->defline, sp->lastline, snlines, fsp->name); printname(sp); putchar('\n'); } else { printf("%d\t%d\t%d\t%d\t%d\t", cycloswitch, cyclocase, sp->nstatements, sp->firstline, snlines); printf("%s(%d): ", fsp->name, sp->defline); printname(sp); printf("\n"); } break; case STATS_CLASS: abort(); if (Softbuild) { } else if (Cyco) { } else { } break; } }