• Linux
  • May 2024
    M T W T F S S
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
  • Meta

Cascadia Code font

Yesterday my son posted a tweet linking to an article about the new Microsoft Cascadia Code font, a monospaced font that includes programming ligatures. He said that he’d been using it on Windows, MAC, and Linux.

I downloaded the font from Github and installed it on my main system. Then I made it the default font for my terminal and text editors. I had to do a little extra work to get the ligatures to work in the Atom Editor but once I did, I was sold on it. I added the font on my other systems and set it up in my terminals and editors.

The programming ligatures worked straight away in xed and gedit but the Atom Editor required a bit more work. On some of my systems, the ligatures worked great once I place the ‘Cascadia Code’ font at the beginning of the font family list. On a couple of systems, I had to add some code to the ~/.atom/styles.less file:

// style the background and foreground colors on the atom-text-editor-element itself
atom-text-editor {
// color: white;
// background-color: hsl(180, 24%, 12%);

// Enaable Cascadia Code ligatures
text-rendering: optimizeLegibility;

&.editor .syntax–string.syntax–quoted,
&.editor .syntax–string.syntax–regexp {
-webkit-font-feature-settings: “liga” on, “calt” on;
}
}

On Atom installations that didn’t have the styles.less file I didn’t have to do anything, it just worked.

Inspired, I installed the font on my Windows 7 PC and installed Atom on it. Nothing against Notepad++ but I like Atom much better.

I’m quite happy with this font. It looks nice and I like the programming ligatures.

Makefile Fun

Over the last couple of days I’ve been relearning make files. It had been over twenty years since I’d worked with them and even then I generally had trouble with them. I watched several YouTube videos, some better than others, and they started making more sense to me.

Yesterday, I found C Programming Makefiles by Barry Brown. In the video he started with simple cases and gradually increased the complexity. I liked the way he explained the processes involved and put the dependency tree in a graphical format, making it easier to see the relationships between the source code, the object files, and the executable files.

Two days ago, I created a Makefile for the FnLoC/LLoC project and put it in my git repositories. That got me to thinking about breaking the project down into multiple files since both programs used a lot of common code to parse lines from a file and determine the states. I had an idea that I might even be able to put the main part of that common code into a function.

Then yesterday, after I’d watch the Barry Brown video, I copied the files from the local repository into a working directory and started pulling out the common code. Previously, I had considered files to take care of the common functions, the linked list, and some general functions. Ultimately, I decide just to work with the common declarations and functions which I put into files I finally named lstates.h and lstates.c.

With a little work, I got everything to compile and link. I tested the resulting programs and discovered that both programs were counting nearly twice as many lines of code than there actually were, much like when I’d attempted to change the NewLineNC state to NewLine from within the switch statement. I moved the code back into main() in both source files and everything appeared to be working.

With the programs successfully compiled, linked, and tested, I update the change log and the README. In the README I added a listing of the source files under the description. Under Compiling from source, I took out the part about compiling with GCC without the Makefile. Before I split off the common source code, that was a very simple matter but with the addition of the lstates files, I didn’t feel like going through the whole process. I figure if someone is downloading the program, they probably know enough to compile it.

I’m also considering eliminating the fnloc-install.tar.gz archive. If someone who is not on a Debian- or Ubuntu-based distribution wants the program, they can download the source and the scripts and go from them. If anyone wants to create a package for a different distribution, they’re welcome to do it. If anyone does, it would be nice if they’d share it with me

I haven’t had a chance yet to do anything the new source code on Windows yet. I’ll probably take a look at that later this week. I use MinGW gcc on Windows and I’ve had no problems with compilation so I expect that it will be able to deal with the Makefile.

This little multi-file project has been a confidence builder.

FnLoC Updates

In the last couple of days, I’ve done some work on the FnLoC project and made several commits to my GitHub repository.

First of all, it dawned on my why FnLoC wouldn’t work properly with a lof of my source code from my Computer Science coursework 20 years ago. I had written much of that code using Dos and Windows text editors and IDEs. These editors would leave carriage return characters throughout the file. These characters wreaked havoc on my FnLoC program which was developed to work with files written in a Linus or Unix environment.

To solve the problem, I wrote a Bash script (dos2linux) to clean out the carriage returns. The script uses sed to remove the carriage return characters and creates a backup of the original file.


    sed -i.bak -e 's/\r//g' source-file.c

There are some other methods, such as the tr command, but this worked well for me and was easily incorporated into a script.

After going through and cleaning up all of my old CS source code files, I copied the code for my original LOC counting program then updated it so it was consistent with the line parsing process of FnLoC. I also added a couple of functions to print the results and to display syntax help. When I finished, I named it LLoC for “Logical Lines of Code.” While I was at it, I tidied up the FnLoc code a bit, just some minor formatting things I’d missed previously.

I also compiled the new code on my Windows 7 machine and updated the installation and removal batch files before placing them in a zipped archive.

This morning I modified the loc2file Bash script to incorporate LLOC by having it process header files. While going through my old code, I found a number of C++ files with .cc and .hh file extensions so I added those extensions to those extensions to be used.

Then I updated the deb package and updated the documentation. When I was satisfied I had everything up to date, I updated the Git repository and pushed the changes to my GitHub repository.

Looking at FnLoC Code

This afternoon I took a look at my FnLoC source code and saw a couple of lines of code that I thought I could modify a bit.

While the program is parsing a line of source code, it goes through the line character by character, changing the state of the line as it goes. I use a switch statement that looks at every possible state and potentially changes the state based on the state set by the previous character.

One of the possible states is NewLineNC. It’s a transition state that’s usually entered when a newline character is reached from certain states. I’m not exactly sure of its purpose anymore though I’m sure I knew when I wrote the original program back in 1998. I really no longer fully understand how the processes work but I’ve figured out some of it as I’ve been working on it over the past few months.

When I first entered the source code (after 20 years), I got an error or warning from the compiler about NewLineNC state not being among the possible cases. It’s not a state that can be entered until the very end of a line so there’s no function to process it. To satisfy the compiler, I added a case for it that doesn’t do anything.


     switch (state)
     {
        case (NewLineNC) :
            break;
     }

Later in the program, after the line has been parsed, I have a conditional statement that check to see if the final state of the line is NewLineNC. If it is, the state is changed to NewLine which is the initial state of a new line of code.


     if ( state == NewLineNC )
            state = NewLine;

I wondered it I could change the state from NewLineNC to NewLine in the switch case and eliminate the if statement so I gave it a try. After compiling the code, I ran it against my source code file and compared it to the previous LOC information. I immediately noticed a considerable difference.

The total LOC count increased from 245 lines to 276 lines. Counts for several functions increased by one line. The main() function’s count increased by 6 lines and lines of code outside of functions (declarations and compiler directives), increased from 5 lines to 24 lines.

I looked at the code and physically counted the logical lines in several functions, verifying the counts before the changes. I wasn’t able to identify what lines had been added to the count but it was apparent that with the change, the line state was being changed from NewLineNC to NewLine when it shouldn’t have, thus adding lines of code that weren’t really code such as comments. It became quite apparent that the place to change between those states was after the entire line had been processed.

NewLineNC seems to be a possible final state for a processed line while NewLine is an initial state for the line. As I said earlier, I probably understood the code a lot better when I originally wrote it. I’m pretty sure that I had manually parsed many lines of code to determine all of the potential states that could occur in a possible line of code. Since rediscovering the code, I’ve been slowly relearning it and figuring it out.

I undid the changes, leaving it the way it was. I considered adding more comments to help clarify some sections of the code but decided against it. I didn’t really want to recompile it and make a new deb package. I’d do that if there were actual changes to the code itself.

FnLoC on GitHub

A few days ago I discovered that I had a GitHub account. I have no idea when or why I created it. I uploaded fnloc.deb to it but I really wasn’t sure what else I could do with it.

Yesterday I found a good video on GitHub for beginners. I took notes and following the instructions, I was able to create a git repository on my local machine and push it to my GitHub account.

I also found a couple of Markdown cheatsheets and reformatted my README file. I had separate readme files for the .tar.gz and the Windows packages, the main difference among them being the installation and removal instructions so I included them.

First I pushed version 2.2 (the version that introduced the singly linked list) as my initial commit, establishing a base version. Then I committed the changes for version 2.2.1 which is the current version.

FnLoC version 2.2.1 now displays the second line of a function header if it has been spit into two lines. The previous version accounted for such lines but only displayed the first line. I added a second variable in main() and in the data structure to hold the string containing the second line then set up a switch statement to consider the cases where the line being read is in the PosFunction state and the first character of the line is {, }, or white space and take the appropriate actions. In the function that displays the results, I put in a conditional statement to test if the second string was empty and, if not, print the string.

I’m still not quite satisfied with the way multi-line comma-delimited declarations, such as arrays and enumerated types, are counted. For example:


int daysMon[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

is counted as a single line of code, as it should be. However, if the declaration is split into two or more lines, the program counts it as two lines of code (the first and last lines).


int daysMon[12] = {
    31, 28, 31, 30,
    31, 30, 31, 31,
    30, 31, 30, 31
};

To my thinking, the second example should be counted a one logical line of code. I’m pondering that problem and looking for a solution. I’m open to ideas.

FnLoC v2.2

I’m not certain what version the program really is. I’d made several modifications to the original program some 20 years ago and apparently some of the early source code is missing. I know there was once a version 1.3 that listed the functions in the same order as they appeared in the target source code.

The last version was dubbed version 2.1.2 and since the code I finished today is so much different, I decided to make it 2.2. Maybe there’s enough difference to make it a major revision and call it 3.0. I don’t know.

I did some research and refreshed my knowledge of linked lists. Once I felt reasonably comfortable with them, I set out to implement a singly linked list to replace the stack. The primary motivation was to list functions in the output in the same order as they appeared in the target source code file. Using a stack (first in, last out), the functions were listed in reverse order.

A side benefit was that I needed fewer functions to implement the linked list since all I needed to do was to add data to the end of the list , display the output, and then free the memory when I was done.

In process of implementing the list, I simplified my data structures for holding the function data. Instead of a struct containing the data in main(), I used a couple of simple variables to hold the data until it was put into the list. Much easier to manage.

Most of the code for parsing a line of code and determining states was left intact since it was already working well. I did tweak the code for determining the possible states a function could be in because, for some reason, it would sometimes display main() with name of the next function encountered. The count would be right but the name would be wrong. Fixing the problem was a matter of changing one if condition. I’d been suspicious of that line for a while.

Finally, I split up the function that displayed the data in to three different functions, based on the the information they displayed. One prints a header to identify the program and display some introductory information. Next came the function that displayed the function data, if any. Finally, there was the function that printed a summary of the counts.

After testing it, I updated the documentation and the installation package (.tar.gz). The next step is to compile it in Windows and update the Windows package. I should be able to translate the Bash script that redirects the output to a text file into a Windows batch file without too much trouble.

Feelin’ the need to code

Yesterday, I felt the need to code something so I wrote a little program to convert between Celsius and Fahrenheit. Writing functions to do the conversions was easy but it took me a while to figure out how I wanted to input the data. I thought about creating prompts within the program, maybe inside a loop for multiple conversions. What I really wanted to do was get the input from command line arguments.

With a little on-line research, I figured out how to get a number from the command line using strtol() and strtod() and using the results of those functions to determine the validity of the return value.

To get the temperature scale (Celsius or Fahrenheit) to convert from, I started off using the tests I used in FnLoC to call the help function and expanded on it to call the appropriate conversion functions. That resulted in a cumbersome set if nested if-else statements but it worked.

I took another look at the program and decided that replacing the nested if-else statements with a switch() would be better. I created a local variable to hold the command line argument and passed the first character of the string to switch(). If that character isn’t f, F, c or C, it defaults to printing an error message and calling up the help function to show the proper syntax.

It’s a rather mundane and basic program but it was a learning experience and a step forward in relearning the language.

The program has 60 lines of code with 52 lines in four functions (including main). The other eight lines are compiler directives (#include) and function declarations.

 

FNLOC – Counting Code

As I’ve noted in recent posts and tweets, my interest in C coding has been revitalized. A couple of weeks ago I found some source code from my college Computer Science and Computer Engineering courses. Of particular interest were my programs that counted lines of code in C source files. I re-entered the code, compiled it and started working with it and studying it.

As I recall the original class assignment was to write a program (loc.c) that simply counted lines of code, ignoring comments and blank lines. The follow-up to that assignment was to enhance the original program (fnloc.c) to identify functions and count the lines of code within them.

The program’s output is a listing of all the functions with their respective lines of code and then a summary showing how many functions it finds and the total lines of code in functions, how many lines of code located outside functions (compiler directives and global declarations), and the total number of lines in the code. I found the second program useful and I made a few minor modifications to it even after the class concluded.

After resurrecting the code I found myself trying to understand how the code works and the logic behind it. I ran the program against various source files and compared the results with my manual code counts. I found discrepancies between the counts and started looking at the code to see why some lines of code weren’t being counted correctly. See Revisiting Old Code and the accompanying comments for more details.

I created README and CHANGELOG files for the program to detail pertinent information and create a chronological history of the changes. I also read up on C code styling standards and formalize the style I use which is predominantly what Kernighan and Ritchie used in The C Programming Language, 2nd Edition along with some sage advice from Linux Kernel Coding Style by Linus Torvalds. Naturally, my style works well with my program. But nearly any C source file written in the K&R style should work.

I’ve corrected most of the problems I’ve discovered but there are a few limitations and requirements.

Functions should be written in the following general format:


int function(int x)
{
    body of function
}

Data structures and array definitions (unless they fit on a single line) should have a format similar this:


struct {
    int len;
    char *str;
} *p;

Essentially, any line where an open brace is the first character of the next non-blank line will be processed as a function.

Conditional statements and for loops without an opening brace a the end of the line will be counted as a single line of code once and ending semi-colon is reached. Each of the following examples are seen as single lines of code:


if (condition)
    action;

for (i=1; i < 10; i++)
    if (condition)
        action;

if (condition) {
    action1;
    action2;
}
else 
    action3;

In the last example, the if (condition), action1, and action2 are separate lines of code. The else action3 is seen as one line of code.

For now, I’m considering this to be acceptable behavior. In my mind, I can see each of those constructs as single logical lines of code. I can live with that.

I’ve tried several different things to force the program to see each line containing code as a line of code but so far none of them have worked. The code, as written, seems like it should recognize the above constructs as multiple code lines but it doesn’t. It’s been over 20 years since I wrote the original code so my understanding of how it works may not be as clear as it was then. For that matter, it’s possible that I may not have fully understood it then either.

My renewed interest in writing code is mostly for my own enjoyment and to keep my mind active. Around the time I dropped out of the Computer Science program, it had become tedious but that was probably because at that point, I was only taking one class at a time and it was difficult to recall when I’d taken the prerequisite classes, let alone what I might have learned in them.

I don’t think I ever really lost my interest in writing code. Since then I’ve worked with HTML and CSS, DOS batch files and Powershell, and, for the last couple of years, Bash scripts. Generally, I’ve done them in the pursuit of my own interests or to accomplish a particular task with no pressure to produce anything or meet anyone’s expectations.

Revisiting Old Code

I recently found some of my C programming books, reviving my interest. It’s been nearly 20 years since I’ve written any source code and I’m quite rusty. A couple of my books and the copy of The C Programming, Second Edition by Kernighan & Ritchie were written in the late 1980s and early 1990s and many of the example program listings don’t conform to modern C standards which makes relearning C a bit more challenging. It also doesn’t help that I don’t remember much from my programming classes and such.

I happened to find a notebook contain some of the source code I wrote as a student. Much of that code no longer makes much sense to me, largely because I’m no longer familiar with the mathematical problems they were meant to solve and I don’t remember much about C data structures either.

I did find my source code for a program I wrote that reads a text file of C or C++ source code and counts how many lines of code it contains disregarding comments and blank lines, and displays the result.

I later modified the program to identify functions and count their lines of code. This program listed all of the functions and their respective counts, then displayed a summary of the total number of functions, total lines of code contained in functions, and total lines of code for the program.

I haven’t been able to locate the original source files so I’ve been typing them into an editor from my printed source code. I’m very prone to making typographical errors so proofreading and fixing the code can get tedious. It’s fortunate that I had the foresight to thoroughly document the original code to include function descriptions, parameters, outputs, possible side effects and limitation. I think I made three versions of the second program but I can only find the source for the first two versions.

I got the program that simply counts the lines of code (loc.c) compiles and it works. I even made a couple modifications to the displayed output. I entered the code for the second version of the function counting program (fn_loc.c) and got it to compile. However, I immediately get a segmentation fault when I try to run it. I know that it worked when I wrote it 20 years ago. I used it to print out summaries of the programs in my notebook.

The fn_loc.c program uses a stack to store a simple data structure containing the name of each function and its lines of code count and that’s where I suspect the problem lies. It’s probably a misplaced pointer.

I did a little research on debugging and recompiled the code with the debugging information included:

$ gcc -ggdb -Wall -o fn_loc fn_loc.c

Without even running the gdb debugger, the compiler’s output pointed me to the line containing my error in the function that created the stack:

s – (STACK)malloc(sizeof (struct node));

The error was obvious. The ‘-‘ should have been ‘=’. The stack was never created and the variable ‘s’ was never initialized. I corrected the error, recompiled it, and the program ran perfectly.

The compiler showed another error that I don’t quite understand:

fn_loc.c: In function ‘main’:
fn_loc.c:103:5: warning: enumeration value ‘NewLineNC’ not handled in switch [-Wswitch]
switch(state)

NewLineNC is one of the enumerated type values I created to track the state of the line being examined. It’s used as a transitory state in several of the functions that determine the new state after a character has been examined. I don’t seem to have an need for in in main().

That program was one of the more useful programs I wrote in school and I enjoyed writing it.

My renewed interest in programming is mostly for my own enjoyment, something to challenge my mind and keep it active. Of all the languages I used in school, C was my favorite and my go to language if I had a choice. I dabbled in Ada, C++, Java, Lisp, Pascal, and Visual Basic but only learned enough to complete assignments. Even C was self-taught. I spent a lot of time looking up functions in my Borland compiler manual or other reference books.