File:  [Coherent Logic Development] / freem / src / fma_routines.c
Revision 1.4: download - view: text, annotated - select for diffs
Sat Mar 22 18:43:54 2025 UTC (10 days, 5 hours ago) by snw
Branches: MAIN
CVS tags: v0-62-3, v0-62-2, HEAD
Make STRLEN 255 chars and add BIGSTR macro for larger buffers

/*
 *   $Id: fma_routines.c,v 1.4 2025/03/22 18:43:54 snw Exp $
 *    fmadm - routines
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2023, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM 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 Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: fma_routines.c,v $
 *   Revision 1.4  2025/03/22 18:43:54  snw
 *   Make STRLEN 255 chars and add BIGSTR macro for larger buffers
 *
 *   Revision 1.3  2025/03/09 19:14:25  snw
 *   First phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later
 **/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>

#include "fmadm.h"
#include "iniconf.h"

int fma_do_export (FILE *out, char *rtn_name);
char *fma_trim_string(char *str);

int fma_routines_list (int optc, char **opts)
{

    DIR *dir;
    struct dirent *ent;

    char filename[PATHLEN];
    char *rtnname;
    char *rtnext;

    int ct = 0;

    printf ("\nFreeM Routine Listing\n");
    printf ("---------------------\n\n");

    printf ("Namespace:     %s\n", fma_namespace);
    printf ("Routine Path:  %s\n\n", fma_routine_path);

    if ((dir = opendir (fma_routine_path)) == NULL) {
        fprintf (stderr, "fmadm:  could not open routine directory %s\n", fma_routine_path);
        return 1;
    }

    while ((ent = readdir (dir)) != NULL) {

        strncpy (filename, ent->d_name, PATHLEN - 1);

        rtnname = strtok (filename, ".");
        rtnext = strtok (NULL, ".");

        if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
            printf (" %s\n", rtnname);
            ct++;
        }

    }

    printf ("\n\n    - %d routines found\n\n", ct);
    closedir (dir);

    return 0;

}

int fma_routines_edit (int optc, char **opts)
{
    FILE *fp;
    char rpath[PATHLEN];
    char ecmd[STRLEN];
    char *editor;

    if (optc < fma_min_args) {
        fprintf (stderr, "fmadm:  must supply routine name\n");
        return 1;
    }


    if ((editor = getenv("EDITOR")) == NULL) {
        
        if ((editor = (char *) malloc (3 * sizeof (char))) == NULL) {
            fprintf (stderr, "fmadm:  could not acquire memory\n");
            return 1;
        }
        
        strncpy (editor, "vi", 3);

    }

    snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);

    if (file_exists (rpath) == FALSE) {
        if ((fp = fopen (rpath, "w")) == NULL) {
            fprintf (stderr, "fmadm:  error %d creating routine %s (%s)\n", errno, opts[1], strerror (errno));

            return 1;
        }

        fprintf (fp, "%s ; Created by FreeM Administrator\n    QUIT\n", opts[1]);
        fclose (fp);
       
    }

    snprintf (ecmd, STRLEN - 1, "%s %s", editor, rpath);
    system (ecmd);

    return 0;

}

int fma_routines_examine (int optc, char **opts)
{

    FILE *fp;
    char c;
    char rpath[PATHLEN];
    /* char *editor; */

    if (optc < fma_min_args) {
        fprintf (stderr, "fmadm:  must supply routine name\n");
        return 1;
    }

    snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[fma_base_opt]);

    if (file_exists (rpath) == FALSE) {
        fprintf (stderr, "fmadm:  routine %s does not exist in namespace %s\n", opts[1], fma_namespace);
        return 1;
    }

    if ((fp = fopen (rpath, "r")) == NULL) {
        fprintf (stderr, "fmadm:  could not open routine %s\n", opts[1]);        
        return 1;
    }

    while ((c = fgetc (fp)) != EOF) putchar (c);

    fclose (fp);

    putchar ('\n');

    return 0;

}

int fma_routines_backup (int optc, char **opts)
{
    time_t t = time (NULL);
    struct tm *buf;
    char rcmd[STRLEN];
    char backup_filename[PATHLEN];
    char dtstamp[STRLEN];
    char bup_path[PATHLEN];

    buf = gmtime (&t);

    if (optc > 1) {
        strncpy (bup_path, opts[fma_base_opt], PATHLEN - 1);
    }
    else {
        strncpy (bup_path, "/tmp", PATHLEN - 1);
    }

    snprintf (dtstamp, STRLEN - 1, "%d%02d%02d%02d%02d%02d", buf->tm_year, buf->tm_mon, buf->tm_mday, buf->tm_hour, buf->tm_min, buf->tm_sec);
    snprintf (backup_filename, PATHLEN - 1, "%s/freem-routines-backup-%s-%s.tar", bup_path, fma_namespace, dtstamp);

    printf ("\nFreeM Routine Backup\n");
    printf ("--------------------\n\n");

    printf ("Namespace:        %s\n", fma_namespace);
    printf ("Routine Path:     %s\n", fma_routine_path);
    printf ("Backup Location:  %s\n", bup_path);
    printf ("Backup Filename:  %s\n\n", backup_filename);

    snprintf (rcmd, STRLEN - 1, "tar cvf %s %s/*.m", backup_filename, fma_routine_path);
    system (rcmd);

    printf ("\n\nBackup completed.\n\n");

    return 0;

}

int fma_routines_restore (int optc, char **opts)
{
    return 0;
}

char *fma_trim_string(char *str)
{

    char *end;

    while (isspace ((unsigned char) *str)) str++;

    if (*str == 0) return str;

    end = str + strlen (str) - 1;

    while (end > str && isspace ((unsigned char) *end)) end--;

    end[1] = '\0';

    return str;

}

int fma_routines_import (int optc, char **opts)
{
    int usr_loaded = 0;
    int pct_loaded = 0;
    int next_routine_flag = FALSE;
    int rtn_open = FALSE;
    int rtn_overwrite = TRUE;
    long ln = 0;

    char pct_rtn_path[4096];
    char usr_rtn_path[4096];
    char namespace[4096];
    char roufile[4096];
    char line[STRLEN];  
    char *trimmed_line;
    
    char filename[4096];
    FILE *archive = NULL;
    FILE *rtn = NULL;

    char *parsed_line;
    
    strncpy (namespace, fma_namespace, 512 - 1);
    strncpy (filename, opts[fma_base_opt], 4096 - 1);

    if (optc < fma_min_args) {
        fprintf (stderr, "usage:  fmadm import routine <namespace> <rsav-file>\n");
        return 1;
    }

    if (strncmp (fma_namespace, "SYSTEM", PATHLEN - 1) != 0) {
        
        if (get_conf ("SYSTEM", "routines_path", pct_rtn_path) == FALSE) {
            fprintf (stderr, "fmadm:  could not determine percent routine access path from configuration for namespace '%s'.\n", namespace);

            return 1;
        }

    }
    else {
        strncpy (pct_rtn_path, fma_routine_path, 4096 - 1);
    }


    if (get_conf (namespace, "routines_path", usr_rtn_path) == FALSE) {
        fprintf (stderr, "fmadm:  could not determine user routine access path from configuration for namespace '%s'.\n", namespace);

        return 1;
    }

    if ((archive = fopen (filename, "r")) == NULL) {
        fprintf (stderr, "fmadm:  could not open routine archive '%s'.\n", filename);

        return 1;
    }

    printf ("\nFreeM Routine Import\n");
    printf ("--------------------\n\n");
    
    printf ("Namespace:        %s\n", fma_namespace);
    printf ("Archive:          %s\n", filename);
    printf ("Routine Path:     %s\n", usr_rtn_path);
    printf ("%% Routine Path:   %s\n\n", pct_rtn_path);

    /* read routine archive line-by-line */
    while (fgets(line, STRLEN - 1, archive) != NULL) {

        if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0';

        ln++;

        if ((ln == 1) || (ln == 2)) {
            printf("%s\n", line);
            continue;
        }

        if (ln == 3) {
            next_routine_flag = TRUE;
        }

        trimmed_line = strdup (line);
        
        if (strcmp (fma_trim_string (trimmed_line), "") == 0) {
            
            next_routine_flag = TRUE;
            
            if(rtn_open == TRUE) {
                fclose(rtn);
                
                rtn_open = FALSE;
            }

            continue;
        }
        
        if(next_routine_flag == TRUE) {
            
            next_routine_flag = FALSE;

            parsed_line = strtok (line, "^");
            
            if((!isalpha(line[0])) && (line[0] != '%')) {

                if(rtn_open == TRUE) {
                    fclose(rtn);
                    rtn_open = FALSE;
                }

                continue; 
            }

            printf(" %s\n", parsed_line);

            
            switch(line[0]) {
                
                case '%':
                    pct_loaded++;

                    snprintf(roufile, PATH_MAX, "%s/%s.m", pct_rtn_path, parsed_line);
                    break;

                default:
                    usr_loaded++;

                    snprintf(roufile, PATH_MAX, "%s/%s.m", usr_rtn_path, parsed_line);
                    break;
            }

            if((file_exists(roufile) == TRUE) && (rtn_overwrite == FALSE)) {
                fprintf(stdout, "fmadm:  routine file '%s' already exists. Will not overwrite.\n", roufile);

                fclose (archive);
                
                return 1;
            }

            if((rtn = fopen(roufile, "w")) == NULL) {
                fprintf(stdout, "fmadm:  could not open routine file '%s'.\n", roufile);

                return 1;
            }
            else {
                rtn_open = TRUE;
            }

        }
        else {
            if(rtn_open == TRUE) fprintf(rtn, "%s\n", line);
        }

    }

    printf("\n     - loaded %d user routines and %d percent routines (%d total)\n\n", usr_loaded, pct_loaded, usr_loaded + pct_loaded);

    fclose (archive);
    
    return 0;
}

int fma_routines_export (int optc, char **opts)
{

    FILE *out;      /* output file handle */
    DIR *dir;       /* namespace directory */
    
    struct dirent *ent;
    char output_file[PATHLEN];
    char routine_spec[PATHLEN];
    char filename[PATHLEN];
    char *rtnname;
    char *rtnext;
    int i;

    int ct = 0;


    if (optc < fma_min_args) {
        fprintf (stderr, "usage:  fmadm export routine <namespace> <output-file> [routine1 routine2... routineN]\n");
        return 1;
    }

    /* if routines aren't listed, assume we should export entire namespace */
    if (optc == fma_min_args) {
        strncpy (routine_spec, "*", PATHLEN - 1);
    }

    strncpy (output_file, opts[1], PATHLEN - 1);
    strncpy (routine_spec, opts[2], PATHLEN - 1);

    if (file_exists (output_file) == TRUE) {
        fprintf (stderr, "fmadm:  output file %s already exists\n", output_file);
        return 1;
    }

    if ((out = fopen(output_file, "w")) == NULL) {
        fprintf (stderr, "fmadm:  could not open output file %s for writing\n", output_file);
        return 1;
    }


    printf ("\nFreeM Routine Export\n");
    printf ("--------------------\n\n");

    printf ("Namespace:             %s\n", fma_namespace);
    printf ("Routine Path:          %s\n", fma_routine_path);
    printf ("Output File:           %s\n", output_file);
    printf ("Routines Selected:     ");
    
    if (optc == 2) {
        printf ("[ENTIRE NAMESPACE]\n\n");
    }
    else {
        for (i = 2; i < optc; i++) {
            printf ("%s ", opts[i]);
        }

        printf ("\n\n");
    }

    fprintf (out, "Routines\n");

    if (optc == 2) {

        /* export entire namespace */

        if ((dir = opendir (fma_routine_path)) == NULL) {
            fprintf (stderr, "fmadm:  could not open routine directory %s\n", fma_routine_path);
            fclose (out);
            return 1;
        }

        while ((ent = readdir (dir)) != NULL) {

            strncpy (filename, ent->d_name, PATHLEN - 1);

            rtnname = strtok (filename, ".");
            rtnext = strtok (NULL, ".");

            if (rtnext != NULL && strncmp (rtnext, "m", PATHLEN - 1) == 0) {
                ct += fma_do_export (out, rtnname);
            }

        }

        closedir (dir);

    }
    else {

        /* export only selected routines */
        for (i = fma_base_opt + 1; i < optc; i++) {
            ct += fma_do_export (out, opts[i]);
        }

    }

    printf ("\n\n    - %d routines exported\n\n", ct);

    fclose (out);
    
    return 0;

}

int fma_do_export (FILE *out, char *rtn_name)
{
    FILE *in;
    char rtnfile[PATHLEN];
    char line[FM_STR_MAX];

    snprintf (rtnfile, PATHLEN - 1, "%s/%s.m", fma_routine_path, rtn_name);

    printf (" Exporting %-10s\t", rtn_name);

    if ((in = fopen (rtnfile, "r")) == NULL) {
        printf ("[FAIL]\n");
        return 0;
    }

    fprintf (out, "\n%s\n", rtn_name);

    while (fgets (line, FM_STR_MAX, in) != NULL) {
        fprintf (out, "%s", line);
    }

    printf ("[OK]\n");

    fprintf (out, "\n");

    fclose (in);

    return 1;
}

int fma_routines_create (int optc, char **opts)
{
    return 0;
}

int fma_routines_remove (int optc, char **opts)
{
    
    char rpath[PATHLEN];
    int i;
    int ct = 0;
    int er = 0;
    int tot = 0;

    printf ("\nFreeM Routine Removal\n");
    printf ("---------------------\n\n");

    printf ("Namespace:     %s\n", fma_namespace);
    printf ("Routine Path:  %s\n\n", fma_routine_path);

    for (i = fma_base_opt; i < optc; i++) {
        printf ("%-10s\t", opts[i]);

        snprintf (rpath, PATHLEN - 1, "%s/%s.m", fma_routine_path, opts[i]);

        if (unlink (rpath) == -1) {
            printf ("[FAIL]\n");
            er++;
        }
        else {
            printf ("[OK]\n");
            ct++;
        }

        tot++;
    
    }

    printf ("\nRemoved %d routines [%d errors/%d attempted]\n\n", ct, er, tot);

    return 0;

}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>