/*****************************************************************************/ /* C-c[o]d[e]c[ou]nt.c Count of lines of code. Count of lines of comment. BUILD DETAILS ------------- $ @BUILD_CCDCNT BUILD !compile+link $ @BUILD_CCDCNT LINK !link-only COPYRIGHT --------- Copyright (C) 2015-2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY --------------- 21-JAN-2015 MGD v1.0.0, initial (q&d) development */ /*****************************************************************************/ #define SOFTWAREVN "1.0.0" #define SOFTWARENM "CCDCNT" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # error VAX no longer implemented #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif /* standard C header files */ #include #include #include #include #include #include #include /* VMS header files */ #include #include #include #include #include #include /* macros */ #define FI_LI __FILE__, __LINE__ #define ODS_MAX_FILE_NAME_LENGTH 1024 #define ODS2_MAX_FILE_NAME_LENGTH 255 #define VMSnok(x) (!((x) & STS$M_SUCCESS)) #define VMSok(x) ((x) & STS$M_SUCCESS) #define USHORTPTR __unaligned unsigned short* #define SAME2(ptr,val) (*(USHORTPTR)(ptr) == val) #define SLASHESC(ptr) (*ptr == '\\' && *(ptr+1)) int Debug = 0; char Utility [] = "CCDCNT"; /*****************************************************************************/ /* */ main (int argc, char** argv) { static char Dash80 [] = "-----------------------------------------\ -------------------------------------"; int cnt, size, status, BothCharCount, BothLineCount, CodeCharCount, CodeLineCount, CommentCharCount, CommentLineCount, CommentCount, DoOverAll = 0, ExpFileNameLength, FileCharCount, FileLineCount, PrevCodeCharCount, PrevCommentCharCount, ResFileNameLength, TotalBothCharCount = 0, TotalBothLineCount = 0, TotalCharCount = 0, TotalCodeCharCount = 0, TotalCodeLineCount = 0, TotalCommentCharCount = 0, TotalCommentLineCount = 0, TotalCommentCount = 0, TotalFileCount = 0, TotalLineCount = 0; char ExpFileName [ODS_MAX_FILE_NAME_LENGTH+1], ResFileName [ODS_MAX_FILE_NAME_LENGTH+1]; char *aptr, *cptr, *fsptr, *sptr, *zptr; stat_t statBuf; FILE *fptr; struct FAB SearchFab; struct NAM SearchNam; #ifdef ODS_EXTENDED struct NAML SearchNaml; #endif /* ODS_EXTENDED */ /*********/ /* begin */ /*********/ fsptr = "*.C;0"; for (cnt = 1; cnt < argc; cnt++) { if (argv[cnt][0] == '/') { if (!strcasecmp(argv[cnt],"/overall") || !strcasecmp(argv[cnt],"/brief")) DoOverAll = 1; } else fsptr = argv[cnt]; } SearchFab = cc$rms_fab; SearchFab.fab$l_dna = "*.*;0"; SearchFab.fab$b_dns = 5; #ifdef ODS_EXTENDED SearchFab.fab$l_fna = (char*)-1; SearchFab.fab$b_fns = 0; SearchFab.fab$l_nam = (struct namdef*)&SearchNaml; ENAMEL_RMS_NAML(SearchNaml) SearchNaml.naml$l_long_filename = fsptr; SearchNaml.naml$l_long_filename_size = strlen(fsptr); SearchNaml.naml$l_long_expand = ExpFileName; SearchNaml.naml$l_long_expand_alloc = sizeof(ExpFileName)-1; SearchNaml.naml$l_long_result = ResFileName; SearchNaml.naml$l_long_result_alloc = sizeof(ResFileName)-1; #else /* ODS_EXTENDED */ SearchFab.fab$l_fna = fsptr; SearchFab.fab$b_fns = strlen(fsptr); SearchFab.fab$l_nam = &SearchNam; SearchNam = cc$rms_nam; SearchNam.nam$l_esa = ExpFileName; SearchNam.nam$b_ess = ODS2_MAX_FILE_NAME_LENGTH; SearchNam.nam$l_rsa = ResFileName; SearchNam.nam$b_rss = ODS2_MAX_FILE_NAME_LENGTH; #endif /* ODS_EXTENDED */ if (VMSnok (status = sys$parse (&SearchFab, 0, 0))) return (status); #ifdef ODS_EXTENDED SearchNaml.naml$l_long_ver[SearchNaml.naml$l_long_ver_size] = '\0'; ExpFileNameLength = (SearchNaml.naml$l_long_ver - ExpFileName) + SearchNaml.naml$l_long_ver_size; #else /* ODS_EXTENDED */ SearchNam.nam$l_ver[SearchNam.nam$b_ver] = '\0'; ExpFileNameLength = (SearchNam.nam$l_ver - ExpFileName) + SearchNam.nam$b_ver; #endif /* ODS_EXTENDED */ if (Debug) fprintf (stdout, "ExpFileName %d |%s|\n", ExpFileNameLength, ExpFileName); /*****************/ /* for each file */ /*****************/ while (VMSok (status = sys$search (&SearchFab, 0, 0))) { #ifdef ODS_EXTENDED SearchNaml.naml$l_long_ver[SearchNaml.naml$l_long_ver_size] = '\0'; ResFileNameLength = (SearchNaml.naml$l_long_ver - ResFileName) + SearchNaml.naml$l_long_ver_size; #else /* ODS_EXTENDED */ SearchNam.nam$l_ver[SearchNam.nam$b_ver] = '\0'; ResFileNameLength = (SearchNam.nam$l_ver - ResFileName) + SearchNam.nam$b_ver; #endif /* ODS_EXTENDED */ if (Debug) fprintf (stdout, "ResFileName %d |%s|\n", ResFileNameLength, ResFileName); if (stat (ResFileName, &statBuf) < 0) { fprintf (stdout, "%s-E-ACCESS, %%X%08.08X %s\n", Utility, vaxc$errno, ResFileName); continue; } size = statBuf.st_size; if (Debug) fprintf (stdout, "%d bytes\n", size); if (!(aptr = calloc (1, size+1024))) exit (vaxc$errno); /****************/ /* process file */ /****************/ if ((fptr = fopen (ResFileName, "r", "shr=get")) != NULL) { if (statBuf.st_fab_rfm == FAB$C_VAR || statBuf.st_fab_rfm == FAB$C_VFC) { zptr = (sptr = aptr) + size; while (fgets (sptr, zptr-sptr, fptr)) sptr += strlen(sptr); size = sptr - aptr; } else size = fread (aptr, 1, size, fptr); if (Debug) fprintf (stdout, "%d bytes\n", size); fclose (fptr); if (!TotalFileCount) fprintf (stdout, "\ ------Total------ -----------Code------------ ----------Comment----------\n\ Lines Chars Lines Chars Lines Chars\n\ ------- --------- ------- ---- --------- ---- ------- ---- --------- ----\n\ "); if (size) { BothLineCount = BothCharCount = CodeCharCount = CodeLineCount = CommentCharCount = CommentLineCount = CommentCount = FileCharCount = FileLineCount = PrevCodeCharCount = PrevCommentCharCount = 0; TotalFileCount++; FileCharCount = size; zptr = (cptr = aptr) + size; while (cptr < zptr) { if (SAME2(cptr,'/*')) { /***********/ /* comment */ /***********/ cptr += 2; CommentCharCount += 2; CommentCount++; while (cptr < zptr && !SAME2(cptr,'*/')) { if (SLASHESC(cptr)) { CommentCharCount++; cptr++; } if (*cptr == '\n') { FileLineCount++; BothLineCount++; } if (!isspace(*cptr)) CommentCharCount++; cptr++; } if (cptr < zptr) { CommentCharCount += 2; cptr += 2; } } else if (SAME2(cptr,'//')) { /********************/ /* comment (to EOL) */ /********************/ cptr += 2; CommentCharCount += 2; CommentCount++; // to end of line while (cptr < zptr && *cptr != '\n') { if (SLASHESC(cptr)) { CommentCharCount++; cptr++; } if (!isspace(*cptr)) CommentCharCount++; cptr++; } if (cptr < zptr) cptr++; } else if (*cptr == '\"') { /***********/ /* literal */ /***********/ CodeCharCount++; cptr++; while (cptr < zptr && *cptr != '\"') { if (SLASHESC(cptr)) { CodeCharCount++; cptr++; } else if (*cptr == '\n') { FileLineCount++; BothLineCount++; CodeLineCount++; } CodeCharCount++; cptr++; } if (cptr < zptr) { CodeCharCount++; cptr++; } } else if (*cptr == '\n') { /************/ /* new line */ /************/ FileLineCount++; if (CodeCharCount > PrevCodeCharCount || CommentCharCount > PrevCommentCharCount) { BothLineCount++; if (CodeCharCount > PrevCodeCharCount) CodeLineCount++; PrevCodeCharCount = CodeCharCount; if (CommentCharCount > PrevCommentCharCount) CommentLineCount++; PrevCommentCharCount = CommentCharCount; } cptr++; } else if (!isspace(*cptr)) { /*************************/ /* significant non-space */ /*************************/ CodeCharCount++; cptr++; } else cptr++; } BothCharCount = CodeCharCount + CommentCharCount; TotalBothCharCount += BothCharCount; TotalBothLineCount += BothLineCount; TotalCharCount += FileCharCount; TotalCodeCharCount += CodeCharCount; TotalCodeLineCount += CodeLineCount; TotalCommentCharCount += CommentCharCount; TotalCommentLineCount += CommentLineCount; TotalCommentCount += CommentCount; TotalLineCount += FileLineCount; if (!DoOverAll) { if (strchr(fsptr,'*')) fprintf (stdout, "%s%*.*s\n", ResFileName, 78-ResFileNameLength, 78-ResFileNameLength, Dash80); fprintf (stdout, "%04d %7d %9d %7d %3d%% %9d %3d%% %7d %3d%% %9d %3d%%\n", TotalFileCount, FileLineCount, TotalCharCount, CodeLineCount, CodeLineCount * 100 / BothLineCount, CodeCharCount, CodeCharCount * 100 / BothCharCount, CommentLineCount, CommentLineCount * 100 / BothLineCount, CommentCharCount, CommentCharCount * 100 / BothCharCount); } } else fprintf (stdout, "%s-E-READ, %%X%08.08X %s\n", Utility, vaxc$errno, ResFileName); } else fprintf (stdout, "%s-E-OPEN, %%X%08.08X %s\n", Utility, vaxc$errno, ResFileName); free (aptr); } /**********/ /* report */ /**********/ if (!TotalFileCount) exit (status); if (TotalFileCount > 1) { if (!DoOverAll) fprintf (stdout, "%33.33s OVERALL %36.36s\n", Dash80, Dash80); fprintf (stdout, "%04d %7d %9d %7d %3d%% %9d %3d%% %7d %3d%% %9d %3d%%\n", TotalFileCount, TotalLineCount, TotalCharCount, TotalCodeLineCount, TotalCodeLineCount * 100 / TotalBothLineCount, TotalCodeCharCount, TotalCodeCharCount * 100 / TotalBothCharCount, TotalCommentLineCount, TotalCommentLineCount * 100 / TotalBothLineCount, TotalCommentCharCount, TotalCommentCharCount * 100 / TotalBothCharCount); } if (status == RMS$_NMF) status = SS$_NORMAL; return (status); } /*****************************************************************************/