Search code examples
carraysstringstructgetline

Search and Print all non-duplicate struct names inside input file


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

/* Search and Print all non-duplicate struct names inside input file */
int main(int argc, char *argv[])
{
        char temp[64], buf[64], filename[128], array[1024] = "";
        char *ptr, *line = NULL;
        char *tmp1, *tmp2;
        ssize_t rv;
        size_t len;
        int count = 0;
        FILE *fp;

        if (argc < 2) {
                printf("enter file name at cmd line...\n");
                return -1;
        }

        sprintf(filename, argv[1], strlen(argv[1]));
        fp = fopen(argv[1], "r");
        if (!fp) {
                printf("File could not be opened: %s\n", argv[1]);
                return -1;
        }

        while ((rv = getline(&line, &len, fp)) != -1) {
                ptr = strstr(line, "struct");
                if (ptr) {
                        ptr += strlen("struct");

                        while (*ptr == ' ')
                                ptr++;

                        tmp1 = strchr(ptr, ' ');
                        tmp2 = strchr(ptr, ';');
                        len = 0;

                        if (tmp1 == NULL && tmp2 == NULL) {
                                continue;
                        }
                        else if (tmp1 == NULL && tmp2 != NULL) {
                                len = tmp2 - ptr;
                        }
                        else if (tmp1 != NULL && tmp2 == NULL) {
                                len = tmp1 - ptr;
                        }
                        else if (tmp1 && tmp2) {
                                len = tmp1 < tmp2 ? tmp1 - ptr : tmp2 - ptr;
                        }

                        if (len) {
                                snprintf(temp, len+1, "%s", ptr);

                                if (!strstr(array, temp)) {
                                        sprintf(buf, "%2d. ", count++);
                                        strcat(buf, temp);
                                        strcat(array, buf);
                                        strcat(array, "\n");
                                }
                        }
                }
        }

        fclose(fp);
        if (line)
                free(line);
        printf("%s\n", array);
        return 0;
}

Above program finds struct names correctly, however I see chars like , and ) at the end of output names. How to remove it? Below is sample output:

[root@mnm-server programs]# ./a.out /usr/src/linux/drivers/net/ethernet/smsc/smsc911x.c
 0. smsc911x_data
 1. smsc911x_ops
 2. smsc911x_platform_config
 3. phy_device
 4. mii_bus
 5. net_device
 6. napi_struct
 7. regulator_bulk_data
 8. clk
 9. platform_device
10. smsc911x_data,
11. sk_buff
12. net_device_stats
13. netdev_hw_addr
14. sockaddr
15. ethtool_drvinfo
16. ethtool_eeprom
17. ethtool_ops
18. net_device_ops
19. ures,
20. resource
21. device_node
22. smsc911x_data))
23. dev_pm_ops
24. of_device_id
25. platform_driver

Notice output of line 10 and 22. One approach would be to do strchr for ,, ), ; and remove char from end. However, this is not a clean solution if the number of non-alphabetic characters increases.

NOTE: The best solution I found for this is here.


Solution

  • Thanks to inputs from Daniel Jour, the following code handles all cases of struct name* ptr;, struct name{ };, struct { };

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    /* Search and Print all non-duplicate struct names inside input file */
    int main(int argc, char *argv[])
    {
            char temp[64], buf[64], filename[128], array[1024] = "";
            char *ptr, *line = NULL;
            size_t len;
            int count = 0, flag = 0;
            FILE *fp;
    
            if (argc < 2) {
                    printf("enter file name at cmd line...\n");
                    return EXIT_FAILURE;
            }
    
            sprintf(filename, argv[1], strlen(argv[1]));
            fp = fopen(argv[1], "r");
            if (!fp) {
                    printf("File could not be opened: %s\n", argv[1]);
                    return EXIT_FAILURE;
            }
    
            while ((getline(&line, &len, fp)) != -1) {
                    ptr = flag ? line : strstr(line, "struct ");
                    if (ptr) {
                            if (!flag)
                                    ptr += strlen("struct ");
                            while (*ptr == ' ')
                                    ptr++;
    
                            len = 0;
                            while (isalnum(*ptr) || *ptr == '_' || *ptr == '{' || *ptr == '}') {
                                    if (*ptr == '{') {
                                            flag++;
                                    }
                                    else if (*ptr == '}') {
                                            len = 0;
                                            flag--;
                                            do {
                                                    ptr++;
                                            } while (*ptr == ' ');
                                            ptr--;
                                    }
                                    else if ((*ptr != '{') || (*ptr != '}')) {
                                            len++;
                                    }
                                    ptr++;
                            }
    
                            if (len && !flag) {
                                    ptr -= len;
                                    snprintf(temp, len+1, "%s", ptr);
    
                                    if (!strstr(array, temp)) {
                                            sprintf(buf, "%2d. ", count++);
                                            strcat(buf, temp);
                                            strcat(array, buf);
                                            strcat(array, "\n");
                                    }
                            }
                    }
            }
    
            fclose(fp);
            if (line)
                    free(line);
            printf("%s\n", array);
            return EXIT_SUCCESS;
    }
    

    This program doesn't handle cases like func(struct x, struct y), interested users can fix it or just use grep -o "struct [^ ;,)]\+" # | awk '{print $2}' | sort -u. Output of the above program for pre-processed file hworld.i:

    [root@server]# cat hworld.c
    #include <stdio.h>
    
    int main()
    {
            printf("hello world\n");
            return 0;
    }
    
    [root@server]# gcc -Wall --save-temps hworld.c
    [root@server]# ./find_structs hworld.i
     0. _IO_FILE
     1. _IO_marker
     2. _IO_FILE_plus