Skip to content
Advertisement

How do you create a C program that resembles the nl command in Linux?

I am working on a project to create a C program that acts just like the nl command in Linux, with the exceptions; it only accepts limited options, does not accept dashes to denote standard input, and no need for division of documents into logical pages with headers/footers.

This is a link to an nl manual page: https://ss64.com/bash/nl.html

This is where I am at. The errors I have and cannot for the life of me fix, are as follows:

Line 46: warning: implicit declaration of function 'get_line'; did you mean 'fgetline'? (-Wimplicit-function-declaration)"
Line 46: warning: assignment to 'char *' from 'int' makes pointer from integer without a cast (-Wint-conversion)"
Line 73: error: conflicting types for 'get_line'"
Line 46: note: previous implicit declaration of 'get_line' was here."
note: expected 'const char * restrict' but argument is of type 'char'"

The code I have currently:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

//Preprocessor constants:
#define MAX_LINE_LENGTH 100

//Prototypes:
int process_stream(FILE *fpntr);
char *fgetline(FILE *fpntr);

int main(int argc, char* argv[])
{

    char filename;
    char *first_line;
    FILE *fpntr;

    int c;
    int lineNumber = 1;
    int beginningNum = 1;

    //Check for proper number of arguments:
    if (argc != 2)
    {
        fprintf(stderr, "Usage: firstline FILEn");
        return EXIT_FAILURE;
    }

    //Get source and destination from arguments:
    filename = argv[1];

    //Open file for reading:
    fpntr = fopen(filename, "r");

    //Left out of body to below block:
    fprintf (stderr, "Error opening file %s: %sn",
    filename, strerror(errno));
    return EXIT_FAILURE;
    if ((fpntr = fopen(filename, "r")) == NULL) {
        printf("cannot open file n");
        exit(0);
    }

    //Get first line from file:
    if ((first_line = get_line(fpntr)) == NULL) {
        perror("Error reading line");
        exit(EXIT_FAILURE);
        }
    // Print out line:
    printf("First line in file %s: n%s", filename, 
    first_line);

    //read contents from file
    while ((c = fgetc(fpntr)) != EOF){
        if (beginningNum){
            printf("%d   ", lineNumber);
            beginningNum = 0;
        }

        if (c == 'n'){
            lineNumber++;
            beginningNum = 1;
        }
            printf("%c", c);
    }

    fclose(fpntr);
    return EXIT_SUCCESS;
}
/*Function to get next line from open file and place it as 
  a legal string into
  a line buffer that is created locally and is static so it 
  can be returned.
  Returns pointer to line buffer, or else NIL on error or 
  immediate EOF.*/
char *get_line(FILE *fpntr)
{
  static char line_buff[MAX_LINE_LENGTH];

  //Get first line from file and return
  if (fgets(line_buff, MAX_LINE_LENGTH, fpntr) != NULL)
  return line_buff;
  else
  return NULL;
}
 
//EOF

Advertisement

Answer

I’ve taken this to the shop and hammered it into functional shape:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define MAX_LINE_LENGTH 1024

int main(int argc, char* argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: firstline FILEn");

        return EXIT_FAILURE;
    }

    // argv[n] is type char*
    char* filename = argv[1];

    FILE* fpntr = fopen(filename, "r");

    if (!fpntr) {
        fprintf (stderr, "Error opening file %s: %sn", filename, strerror(errno));
        
        return EXIT_FAILURE;
    }

    if ((fpntr = fopen(filename, "r")) == NULL) {
        printf("cannot open file n");
        exit(0);
    }

    static char line[MAX_LINE_LENGTH];

    if (!fgets(line, MAX_LINE_LENGTH, fpntr)) {
        perror("Error reading line");
        exit(EXIT_FAILURE);
    }

    printf("First line in file %s: n%s", filename, line);

    // Try and declare variables as close as possible to where they're used
    // as it makes figuring out what they are way easier. Types are very
    // important in C!
    int begin = 1;
    size_t lineNumber = 0;
    int c;

    // Note: Would be better to read line by line here instead of individual
    //       characters, fgets has you covered, but this is your call.
    while ((c = fgetc(fpntr)) != EOF){
        if (begin) {
            // You can get printf() to do the formatting for you if you
            // let it with %-4 being 4 wide (%4), left-aligned(%-4)
            // %zu is just the type used by size_t for display
            printf("%-4zu ", lineNumber);
            begin = 0;
        }

        if (c == 'n') {
            lineNumber++;
            begin = 1;
        }

        putc(c, stdout);
    }

    fclose(fpntr);
    
    return EXIT_SUCCESS;
}

It Works on My Machineā„¢ (Clang) and apart from needing to rewind (fseek) after your debugging code to dump the first line, it looks good.

On the whole it only took a few little nudges to get things to fit into place properly. You had the right idea, but a lot of the details were just a tiny bit off.

Unfortunately in C a single character can be the difference between “works fine” and agonizing hours of debugging or a whole slew of compiler errors.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement