/* cfengine for GNU Copyright (C) 1995,1999 Free Software Foundation, Inc. This file is part of GNU cfengine - written and maintained by Mark Burgess, Dept of Computing and Engineering, Oslo College, Dept. of Theoretical physics, University of Oslo This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /*********************************************************************/ /* */ /* TOOLKIT: the "item extension" object library for cfengine */ /* */ /*********************************************************************/ /* The functions in this file are mostly used by "editfiles" commands; * DoEditFile() may need to reset more globals before returning for * them to always work as expected. */ #include "cf.defs.h" #include "cf.extern.h" /*********************************************************************************/ struct Item *ListFromArgs(string) /* Splits a string with quoted components etc */ char *string; { struct Item *ip = NULL; int dquote_level = 0,i = 0; int paren_level = 0; char *sp,lastch = '\0'; char item[bufsize]; bzero(item,bufsize); for (sp = string; *sp != '\0'; sp++) { switch (*sp) { case '\"': if (lastch == '\\') /* Escaped quote */ { sp--; *sp = ')'; continue; } else { if (dquote_level == 0) { dquote_level = 1; continue; } else { dquote_level = 0; continue; } } break; case '(': paren_level++; break; case ')': paren_level--; break; case ',': if (dquote_level == 0 && paren_level == 0) { item[i] = '\0'; i = 0; AppendItem(&ip,item,""); bzero(item,bufsize); continue; } } item[i++] = *sp; lastch = *sp; } AppendItem(&ip,item,""); return ip; } /*********************************************************************/ int OrderedListsMatch(list1,list2) struct Item *list1,*list2; { struct Item *ip1,*ip2; for (ip1 = list1,ip2 = list2; (ip1!=NULL)&&(ip2!=NULL); ip1=ip1->next,ip2=ip2->next) { if (strcmp(ip1->name,ip2->name) != 0) { Debug("OrderedListMatch failed on (%s,%s)\n",ip1->name,ip2->name); return false; } } if (ip1 != ip2) { return false; } return true; } /*********************************************************************/ int IsClassedItemIn(list,item) struct Item *list; char *item; { struct Item *ptr; if ((item == NULL) || (strlen(item) == 0)) { return true; } for (ptr = list; ptr != NULL; ptr=ptr->next) { if (strcmp(ptr->name,item) == 0) { if (IsExcluded(ptr->classes)) { continue; } return(true); } } return(false); } /*********************************************************************/ int IsWildItemIn(list,item) /* Checks whether item matches a list of wildcards */ struct Item *list; char *item; { struct Item *ptr; for (ptr = list; ptr != NULL; ptr=ptr->next) { if (IsExcluded(ptr->classes)) { continue; } if (WildMatch(ptr->name,item)) { Debug("IsWildItem(%s,%s)\n",item,ptr->name); return(true); } } return(false); } /*********************************************************************/ void InsertItemAfter (filestart,ptr,string) struct Item *ptr, **filestart; char *string; { struct Item *ip; char *sp; EditVerbose("Inserting %s \n",string); if ((ip = (struct Item *)malloc(sizeof(struct Item))) == NULL) { CfLog(cferror,"","Can't allocate memory in InsertItemAfter()"); FatalError(""); } if ((sp = malloc(strlen(string)+1)) == NULL) { CfLog(cferror,"","Can't allocate memory in InsertItemAfter()"); FatalError(""); } if (CURRENTLINEPTR == NULL) /* File is empty */ { if (filestart == NULL) { *filestart = ip; ip->next = NULL; } else { ip->next = (*filestart)->next; (*filestart)->next = ip; } strcpy(sp,string); ip->name = sp; ip->classes = NULL; CURRENTLINEPTR = ip; CURRENTLINENUMBER = 1; } else { ip->next = CURRENTLINEPTR->next; CURRENTLINENUMBER++; CURRENTLINEPTR->next = ip; CURRENTLINEPTR = ip; strcpy(sp,string); ip->name = sp; ip->classes = NULL; } NUMBEROFEDITS++; return; } /*********************************************************************/ struct Item *LocateNextItemContaining(list,string) struct Item *list; char *string; { struct Item *ip; for (ip = list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { EditVerbose("Aborting search, regex %s matches line\n",VEDITABORT); return NULL; } if (strstr(ip->name,string)) { return ip; } } return NULL; } /*********************************************************************/ int RegexOK(string) char *string; { regex_t rx; if (CfRegcomp(&rx,string, REG_EXTENDED) != 0) { return false; } regfree(&rx); return true; } /*********************************************************************/ struct Item *LocateNextItemMatching(list,string) struct Item *list; char *string; { struct Item *ip; regex_t rx,rxcache; regmatch_t pmatch; if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return NULL; } for (ip = list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return NULL; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { regfree(&rx); return ip; } } } /* regfree(&rx); */ return NULL; } /*********************************************************************/ struct Item *LocateNextItemStarting(list,string) struct Item *list; char *string; { struct Item *ip; for (ip = list; (ip != NULL); ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); return NULL; } if (strncmp(ip->name,string,strlen(string)) == 0) { return ip; } } return NULL; } /*********************************************************************/ struct Item *LocateItemMatchingRegExp(list,string) struct Item *list; char *string; { struct Item *ip; regex_t rx,rxcache; regmatch_t pmatch; int line = CURRENTLINENUMBER; if (list != NULL) { Debug("LocateItemMatchingRexExp(%s,%s)\n",list->name,string); } if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return NULL; } for (ip = list; (ip != NULL); ip=ip->next, line++) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return NULL; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { EditVerbose("Edit: Search ended at line %d\n",line); EditVerbose("Edit: (Found %s)\n",ip->name); CURRENTLINENUMBER = line; CURRENTLINEPTR = ip; regfree(&rx); return ip; } } } EditVerbose("Edit: Search for %s failed. Current line still %d\n",string,CURRENTLINENUMBER); /* regfree(&rx); */ return NULL; } /*********************************************************************/ struct Item *LocateItemContainingRegExp(list,string) struct Item *list; char *string; { struct Item *ip; regex_t rx,rxcache; regmatch_t pmatch; int line = 1; if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return NULL; } for (ip = list; (ip != NULL); ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return NULL; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { EditVerbose("Search ended at line %d\n",line); CURRENTLINENUMBER = line; CURRENTLINEPTR = ip; regfree(&rx); return ip; } } EditVerbose("Search for %s failed. Current line still %d\n",string,CURRENTLINENUMBER); /* regfree(&rx);*/ return NULL; } /********************************************************************/ int DeleteToRegExp(filestart,string) /* Delete up to but not including a line matching the regex */ struct Item **filestart; char *string; { struct Item *ip, *ip_prev, *ip_end = NULL; int linefound = false; regex_t rx,rxcache; regmatch_t pmatch; Debug2("DeleteToRegExp(list,%s)\n",string); if (CURRENTLINEPTR == NULL) /* Shouldn't happen */ { CfLog(cferror,"File line-pointer undefined during editfile action\n",""); return true; } if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return false; } for (ip = CURRENTLINEPTR; (ip != NULL); ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return false; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { linefound = true; ip_end = ip; break; } } } if (! linefound) { return false; } for (ip_prev = *filestart; ip_prev != CURRENTLINEPTR && ip_prev->next != CURRENTLINEPTR; ip_prev=ip_prev->next) { } for (ip = CURRENTLINEPTR; ip != NULL; ip = CURRENTLINEPTR) { if (ip->name == NULL) { continue; } if (ip == ip_end) { EditVerbose("Edit: terminating line: %s (Done)\n",ip->name); return true; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return false; } EditVerbose("Edit: delete line %s\n",ip->name); NUMBEROFEDITS++; CURRENTLINEPTR = ip->next; if (ip == *filestart) { *filestart = ip->next; } else { ip_prev->next = ip->next; } free (ip->name); free ((char *)ip); } /* regfree(&rx); */ return true; } /*********************************************************************/ /* DeleteItem* function notes: * -They all take an item list and an item specification ("string" argument.) * -Some of them treat the item spec as a literal string, while others * treat it as a regular expression. * -They all delete the first item meeting their criteria, as below. * function deletes item * ------------------------------------------------------------------------ * DeleteItemStarting start is literally equal to string item spec * DeleteItemLiteral literally equal to string item spec * DeleteItemMatching fully matched by regex item spec * DeleteItemContaining containing string item spec */ /*********************************************************************/ int DeleteItemGeneral(list,string,type) struct Item **list; char *string; enum matchtypes type; { struct Item *ip,*last = NULL; int match = 0, matchlen = 0; regex_t rx,rxcache; regmatch_t pmatch; if (list == NULL) { return false; } switch (type) { case literalStart: matchlen = strlen(string); break; case regexComplete: case NOTregexComplete: if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return false; } break; } for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); return false; } switch(type) { case NOTliteralStart: match = (strncmp(ip->name, string, matchlen) != 0); break; case literalStart: match = (strncmp(ip->name, string, matchlen) == 0); break; case NOTliteralComplete: match = (strcmp(ip->name, string) != 0); break; case literalComplete: match = (strcmp(ip->name, string) == 0); break; case NOTliteralSomewhere: match = (strstr(ip->name, string) == NULL); break; case literalSomewhere: match = (strstr(ip->name, string) != NULL); break; case NOTregexComplete: case regexComplete: /* To fix a bug on some implementations where rx gets emptied */ bcopy(&rxcache,&rx,sizeof(rx)); match = (regexec(&rx,ip->name,1,&pmatch,0) == 0) && (pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name)); if (type == NOTregexComplete) { match = !match; } break; } if (match) { if (type == regexComplete || type == NOTregexComplete) { regfree(&rx); } EditVerbose("Deleted item %s\n",ip->name); if (ip == *list) { free((*list)->name); if (ip->classes != NULL) { free(ip->classes); } *list = ip->next; free((char *)ip); NUMBEROFEDITS++; return true; } else { if (ip != NULL) { if (last != NULL) { last->next = ip->next; } free(ip->name); if (ip->classes != NULL) { free(ip->classes); } free((char *)ip); } NUMBEROFEDITS++; return true; } } last = ip; } return false; } /*********************************************************************/ int DeleteItemStarting(list,string) /* delete 1st item starting with string */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,literalStart); } /*********************************************************************/ int DeleteItemNotStarting(list,string) /* delete 1st item starting with string */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,NOTliteralStart); } /*********************************************************************/ int DeleteItemLiteral(list,string) /* delete 1st item which is string */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,literalComplete); } /*********************************************************************/ int DeleteItemMatching(list,string) /* delete 1st item fully matching regex */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,regexComplete); } /*********************************************************************/ int DeleteItemNotMatching(list,string) /* delete 1st item fully matching regex */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,NOTregexComplete); } /*********************************************************************/ int DeleteItemContaining(list,string) /* delete first item containing string */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,literalSomewhere); } /*********************************************************************/ int DeleteItemNotContaining(list,string) /* delete first item containing string */ struct Item **list; char *string; { return DeleteItemGeneral(list,string,NOTliteralSomewhere); } /*********************************************************************/ int CommentItemStarting(list,string,comm,end) struct Item **list; char *string,*comm,*end; { struct Item *ip; char buff[bufsize]; for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); return false; } if (strncmp(ip->name,string,strlen(string)) == 0) { if (strlen(ip->name)+strlen(comm)+strlen(end)+2 > bufsize) { CfLog(cferror,"Bufsize overflow while commenting line - abort\n",""); return false; } if (strncmp(ip->name,comm,strlen(comm))== 0) { continue; } EditVerbose("Commenting %s%s%s\n",comm,ip->name,end); snprintf(buff,bufsize,"%s%s%s",comm,ip->name,end); free(ip->name); if ((ip->name = malloc(strlen(buff)+1)) == NULL) { CfLog(cferror,"malloc in CommentItemStarting\n",""); FatalError("");; } strcpy(ip->name,buff); NUMBEROFEDITS++; return true; } } return false; } /*********************************************************************/ int CommentItemContaining(list,string,comm,end) struct Item **list; char *string,*comm,*end; { struct Item *ip; char buff[bufsize]; for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); return false; } if (strstr(ip->name,string)) { if (strlen(ip->name)+strlen(comm)+strlen(end)+2 > bufsize) { CfLog(cferror,"Bufsize overflow while commenting line - abort\n",""); return false; } if (strncmp(ip->name,comm,strlen(comm))== 0) { continue; } EditVerbose("Commenting %s%s%s\n",comm,ip->name,end); snprintf(buff,bufsize,"%s%s%s",comm,ip->name,end); free(ip->name); if ((ip->name = malloc(strlen(buff)+1)) == NULL) { CfLog(cferror,"malloc in CommentItemContaining\n",""); FatalError("");; } strcpy(ip->name,buff); NUMBEROFEDITS++; return true; } } return false; } /*********************************************************************/ int CommentItemMatching(list,string,comm,end) struct Item **list; char *string,*comm,*end; { struct Item *ip; char buff[bufsize]; regex_t rx,rxcache; regmatch_t pmatch; if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return false; } for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return false; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { if (strlen(ip->name)+strlen(comm)+strlen(end)+2 > bufsize) { CfLog(cferror,"Bufsize overflow while commenting line - abort\n",""); regfree(&rx); return false; } if (strncmp(ip->name,comm,strlen(comm)) == 0) /* Already commented */ { continue; } EditVerbose("Commenting %s%s%s\n",comm,ip->name,end); snprintf(buff,bufsize,"%s%s%s",comm,ip->name,end); free(ip->name); if ((ip->name = malloc(strlen(buff)+1)) == NULL) { CfLog(cferror,"malloc in CommentItemContaining\n ",""); FatalError("");; } strcpy(ip->name,buff); NUMBEROFEDITS++; regfree(&rx); return true; } } } /* regfree(&rx); */ return false; } /********************************************************************/ int UnCommentItemMatching(list,string,comm,end) struct Item **list; char *string,*comm,*end; { struct Item *ip; char *sp, *sp1, *sp2, *spc; regex_t rx,rxcache; regmatch_t pmatch; if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { snprintf(OUTPUT,bufsize,"Failed to compile expression %s",string); CfLog(cferror,OUTPUT,""); return false; } for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { if (strlen(ip->name)+strlen(comm)+strlen(end)+2 > bufsize) { CfLog(cferror,"Bufsize overflow while commenting line - abort\n",""); regfree(&rx); return false; } if (strstr(ip->name,comm) == NULL) { CURRENTLINEPTR = ip->next; continue; } EditVerbose("Uncomment line %s\n",ip->name); CURRENTLINEPTR = ip->next; if ((sp = malloc(strlen(ip->name)+2)) == NULL) { CfLog(cferror,"No Memory in UnCommentNLines\n","malloc"); regfree(&rx); return false; } spc = sp; for (sp1 = ip->name; isspace((int)*sp1); sp1++) { *spc++ = *sp1; } *spc = '\0'; sp2 = ip->name+strlen(ip->name); if ((strlen(end) != 0) && (strstr(ip->name,end) != NULL)) { for (sp2 = ip->name+strlen(ip->name); strncmp(sp2,end,strlen(end)) != 0; sp2--) { } *sp2 = '\0'; } strcat(sp,sp1+strlen(comm)); if (sp2 != ip->name+strlen(ip->name)) { strcat(sp,sp2+strlen(end)); } if (strcmp(sp,ip->name) != 0) { NUMBEROFEDITS++; } free(ip->name); ip->name = sp; regfree(&rx); return true; } } } /* regfree(&rx); */ return false; } /********************************************************************/ int UnCommentItemContaining(list,string,comm,end) struct Item **list; char *string,*comm,*end; { struct Item *ip; char *sp, *sp1, *sp2, *spc; for (ip = *list; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } if (strstr(ip->name,string)) { if (strstr(ip->name,comm) == NULL) { CURRENTLINEPTR = ip->next; continue; } EditVerbose("Uncomment line %s\n",ip->name); CURRENTLINEPTR = ip->next; if ((sp = malloc(strlen(ip->name)+2)) == NULL) { CfLog(cferror,"No memory in UnCommentNLines\n","malloc"); return false; } spc = sp; for (sp1 = ip->name; isspace((int)*sp1); sp1++) { *spc++ = *sp1; } *spc = '\0'; sp2 = ip->name+strlen(ip->name); if ((strlen(end) != 0) && (strstr(ip->name,end) != NULL)) { for (sp2 = ip->name+strlen(ip->name); strncmp(sp2,end,strlen(end)) != 0; sp2--) { } *sp2 = '\0'; } strcat(sp,sp1+strlen(comm)); if (sp2 != ip->name+strlen(ip->name)) { strcat(sp,sp2+strlen(end)); } if (strcmp(sp,ip->name) != 0) { NUMBEROFEDITS++; } free(ip->name); ip->name = sp; return true; } } return false; } /********************************************************************/ int CommentToRegExp(filestart,string,comm,end) /* Delete up to and including a line matching the regex */ struct Item **filestart; char *string, *comm, *end; { struct Item *ip, *ip_end = NULL; int linefound = false, done; char *sp; regex_t rx,rxcache; regmatch_t pmatch; Debug2("CommentToRegExp(list,%s %s)\n",comm,string); if (CURRENTLINEPTR == NULL) /* Shouldn't happen */ { CfLog(cferror,"File line-pointer undefined during editfile action\n",""); return true; } if (CfRegcomp(&rxcache,string, REG_EXTENDED) != 0) { return false; } for (ip = CURRENTLINEPTR; (ip != NULL); ip=ip->next) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); regfree(&rx); return false; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(ip->name))) { linefound = true; ip_end = ip; break; } } } if (! linefound) { return false; } done = false; for (ip = CURRENTLINEPTR; ip != NULL; ip = CURRENTLINEPTR) { if (ip == ip_end) { EditVerbose("Terminating line: %s (Done)\n",ip->name); done = true; } EditVerbose("Comment line %s%s%s\n",comm,ip->name, end); NUMBEROFEDITS++; CURRENTLINEPTR = ip->next; if ((sp = malloc(strlen(ip->name)+strlen(comm)+strlen(end)+2)) == NULL) { CfLog(cferror,"No memory in CommentToRegExp\n","malloc"); regfree(&rx); return false; } strcpy (sp,comm); strcat (sp,ip->name); strcat (sp,end); free (ip->name); ip->name = sp; if (done) { break; } } /* regfree(&rx); */ return true; } /********************************************************************/ int DeleteSeveralLines (filestart,string) /* Deletes up to N lines from current position */ struct Item **filestart; char *string; { struct Item *ip, *ip_prev; int ctr, N = -99, done = false; Debug2("DeleteNLines(list,%s)\n",string); sscanf(string,"%d", &N); if (N < 1) { snprintf(OUTPUT,bufsize*2,"Illegal number value in DeleteNLines: %s\n",string); CfLog(cferror,OUTPUT,""); return false; } if (CURRENTLINEPTR == NULL) /* Shouldn't happen */ { CfLog(cferror,"File line-pointer undefined during editfile action\n",""); return true; } for (ip_prev = *filestart; ip_prev && ip_prev->next != CURRENTLINEPTR; ip_prev=ip_prev->next) { } ctr = 1; for (ip = CURRENTLINEPTR; ip != NULL; ip = CURRENTLINEPTR) { if (ip->name == NULL) { continue; } if (EDABORTMODE && ItemMatchesRegEx(ip->name,VEDITABORT)) { Verbose("Aborting search, regex %s matches line\n",VEDITABORT); return false; } if (ctr == N) { EditVerbose("Terminating line: %s (Done)\n",ip->name); done = true; } EditVerbose("Delete line %s\n",ip->name); NUMBEROFEDITS++; CURRENTLINEPTR = ip->next; if (ip_prev == NULL) { *filestart = ip->next; } else { ip_prev->next = ip->next; } free (ip->name); free ((char *)ip); ctr++; if (done) { break; } } if (ctr-1 < N) { snprintf(OUTPUT,bufsize*2,"DeleteNLines deleted only %d lines (not %d)\n",ctr-1,N); CfLog(cfsilent,OUTPUT,""); } return true; } /********************************************************************/ struct Item *GotoLastItem (list) struct Item *list; { struct Item *ip; CURRENTLINENUMBER=1; CURRENTLINEPTR=list; for (ip = list; ip != NULL && ip->next != NULL; ip=ip->next) { CURRENTLINENUMBER++; } CURRENTLINEPTR = ip; return ip; } /********************************************************************/ int LineMatches (line,regexp) char *line, *regexp; { regex_t rx,rxcache; regmatch_t pmatch; if (CfRegcomp(&rxcache,regexp, REG_EXTENDED) != 0) { return false; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,line,1,&pmatch,0) == 0) { /* Exact match of whole line */ if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(line))) { regfree(&rx); return true; } } regfree(&rx); return false; } /********************************************************************/ int GlobalReplace(liststart,search,replace) struct Item **liststart; char *search, *replace; { int i; char *sp, *start = NULL; struct Item *ip; struct Item *oldCurrentLinePtr; regex_t rx,rxcache; regmatch_t match,matchcheck; EditVerbose("Checking for replace/%s/%s\n",search,replace); if (CfRegcomp(&rxcache,search,REG_EXTENDED) != 0) { return false; } for (ip = *liststart; ip != NULL; ip=ip->next) { if (ip->name == NULL) { continue; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,ip->name,1,&match,0) == 0) { start = ip->name + match.rm_so; } else { continue; } bzero(VBUFF,bufsize); i = 0; for (sp = ip->name; *sp != '\0'; sp++) { if (sp != start) { VBUFF[i] = *sp; } else { sp += match.rm_eo - match.rm_so - 1; VBUFF[i] = '\0'; strcat(VBUFF,replace); i += strlen(replace)-1; bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,sp,1,&match,0) == 0) { start = sp + match.rm_so; } else { start = 0; } } i++; } Debug("Replace:\n (%s)\nwith (%s)\n",ip->name,VBUFF); if (regexec(&rx,VBUFF,1,&matchcheck,0) == 0) { snprintf(OUTPUT,bufsize*2,"WARNING: Non-convergent edit operation ReplaceAll [%s] With [%s]",replace,search); CfLog(cferror,OUTPUT,""); snprintf(OUTPUT,bufsize*2,"Line begins [%.40s]",ip->name); CfLog(cferror,OUTPUT,""); CfLog(cferror,"Replacement matches search string and will thus replace every time - edit was not done",""); return false; } CURRENTLINEPTR = ip; InsertItemAfter(liststart,ip,VBUFF); oldCurrentLinePtr = CURRENTLINEPTR; /* set by Insert */ DeleteItem(liststart,ip); ip = oldCurrentLinePtr; } regfree(&rxcache); return true; } /********************************************************************/ int CommentSeveralLines (filestart,string,comm,end) /* Comments up to N lines from current position */ struct Item **filestart; char *string, *comm, *end; { struct Item *ip; int ctr, N = -99, done = false; char *sp; Debug2("CommentNLines(list,%s)\n",string); sscanf(string,"%d", &N); if (N < 1) { snprintf(OUTPUT,bufsize*2,"Illegal number value in CommentNLines: %s\n",string); CfLog(cferror,OUTPUT,""); return false; } if (CURRENTLINEPTR == NULL) /* Shouldn't happen */ { snprintf(OUTPUT,bufsize*2,"File line-pointer undefined during editfile action\n"); CfLog(cferror,OUTPUT,""); return true; } ctr = 1; for (ip = CURRENTLINEPTR; ip != NULL; ip = CURRENTLINEPTR) { if (ip->name == NULL) { continue; } if (ctr > N) { break; } if (ctr == N) { EditVerbose("Terminating line: %s (Done)\n",ip->name); done = true; } for (sp = ip->name; isspace((int)*sp); sp++) { } if (strncmp(sp,comm,strlen(comm)) == 0) { CURRENTLINEPTR = ip->next; ctr++; continue; } EditVerbose("Comment line %s\n",ip->name); NUMBEROFEDITS++; CURRENTLINEPTR = ip->next; if ((sp = malloc(strlen(ip->name)+strlen(comm)+strlen(end)+2)) == NULL) { CfLog(cferror,"No memory in CommentNLines\n","malloc"); return false; } strcpy (sp,comm); strcat (sp,ip->name); strcat (sp,end); free (ip->name); ip->name = sp; ctr++; if (done) { break; } } if (ctr-1 < N) { snprintf(OUTPUT,bufsize*2,"CommentNLines commented only %d lines (not %d)\n",ctr-1,N); CfLog(cfinform,OUTPUT,""); } return true; } /********************************************************************/ int UnCommentSeveralLines (filestart,string,comm,end) /* Comments up to N lines from current position */ struct Item **filestart; char *string, *comm, *end; { struct Item *ip; int ctr, N = -99, done = false; char *sp, *sp1, *sp2, *spc; Debug2("UnCommentNLines(list,%s)\n",string); sscanf(string,"%d", &N); if (N < 1) { snprintf(OUTPUT,bufsize*2,"Illegal number value in CommentNLines: %s\n",string); CfLog(cferror,OUTPUT,""); return false; } if (CURRENTLINEPTR == NULL) /* Shouldn't happen */ { snprintf(OUTPUT,bufsize*2,"File line-pointer undefined during editfile action\n"); CfLog(cferror,OUTPUT,""); return true; } ctr = 1; for (ip = CURRENTLINEPTR; ip != NULL; ip = CURRENTLINEPTR) { if (ip->name == NULL) { continue; } if (ctr > N) { break; } if (ctr == N) { EditVerbose("Terminating line: %s (Done)\n",ip->name); done = true; } if (strstr(ip->name,comm) == NULL) { CURRENTLINEPTR = ip->next; ctr++; continue; } EditVerbose("Uncomment line %s\n",ip->name); CURRENTLINEPTR = ip->next; if ((sp = malloc(strlen(ip->name)+2)) == NULL) { CfLog(cferror,"No memory in UnCommentNLines\n","malloc"); return false; } spc = sp; for (sp1 = ip->name; isspace((int)*sp1); sp1++) { *spc++ = *sp1; } *spc = '\0'; sp2 = ip->name+strlen(ip->name); if ((strlen(end) != 0) && (strstr(ip->name,end) != NULL)) { for (sp2 = ip->name+strlen(ip->name); strncmp(sp2,end,strlen(end)) != 0; sp2--) { } *sp2 = '\0'; } strcat(sp,sp1+strlen(comm)); if (sp2 != ip->name+strlen(ip->name)) { strcat(sp,sp2+strlen(end)); } ctr++; if (strcmp(sp,ip->name) != 0) { NUMBEROFEDITS++; } free(ip->name); ip->name = sp; if (done) { break; } } if (ctr-1 < N) { snprintf(OUTPUT,bufsize*2,"CommentNLines commented only %d lines (not %d)\n",ctr-1,N); CfLog(cfinform,OUTPUT,""); } return true; } /********************************************************************/ int ItemMatchesRegEx(item,regex) char *item, *regex; { regex_t rx,rxcache; regmatch_t pmatch; Debug("ItemMatchesRegEx(%s %s)\n",item,regex); if (CfRegcomp(&rxcache,regex, REG_EXTENDED) != 0) { return true; } bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ if (regexec(&rx,item,1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(item))) { regfree(&rx); return true; } } regfree(&rx); return false; } /********************************************************************/ void ReplaceWithFieldMatch(filestart,field,replace,split,filename) struct Item **filestart; char *field, *replace, *filename; char split; { struct Item *ip; char match[bufsize], linefield[bufsize], *sp, *sps, *spe; int matching_field = 0, fcount, i, linenum, count = 0; Debug("ReplaceWithFieldMatch(%s,%s,%c)\n",field,replace,split); if ((replace == NULL) || (strlen(replace) == 0)) { EditVerbose("Ignoring empty line which doing ReplaceLinesMatchingField\n"); return; } matching_field = atoi(field); bzero(match,bufsize); fcount = 1; sps = spe = NULL; for (sp = replace; *sp != '\0'; sp++) { if (*sp == split) { if (fcount == matching_field) { spe = sp; break; } fcount++; } if ((fcount == matching_field) && (sps == NULL)) { sps = sp; } } if (fcount < matching_field) { CfLog(cfsilent,"File formats did not completely match in ReplaceLinesMatchingField\n",""); snprintf(OUTPUT,bufsize*2,"while editing %s\n",filename); CfLog(cfsilent,OUTPUT,""); return; } if (spe == NULL) { spe = sp; } for (i = 0, sp = sps; sp != spe; i++, sp++) { match[i] = *sp; } Debug2("Edit: Replacing lines matching field %d == \"%s\"\n",matching_field,match); linenum = 1; for (ip = *filestart; ip != NULL; ip=ip->next, linenum++) { bzero(linefield,bufsize); fcount = 1; sps = spe = NULL; if (ip->name == NULL) { continue; } for (sp = ip->name; *sp != '\0'; sp++) { if (*sp == split) { if (fcount == matching_field) { spe = sp; break; } fcount++; } if ((fcount == matching_field) && (sps == NULL)) { sps = sp; } } if (spe == NULL) { spe = sp; } if (sps == NULL) { sps = sp; } for (i = 0, sp = sps; sp != spe; i++, sp++) { linefield[i] = *sp; } if (strcmp(linefield,match) == 0) { EditVerbose("Replacing line %d (key %s)\n",linenum,match); count++; if (strcmp(replace,ip->name) == 0) { continue; } if (count > 1) { snprintf(OUTPUT,bufsize*2,"Several lines in %s matched key %s\n",filename,match); CfLog(cfsilent,OUTPUT,""); } NUMBEROFEDITS++; free(ip->name); ip->name = (char *) malloc(strlen(replace)+1); strcpy(ip->name,replace); EditVerbose("Edit: With (%s)\n",replace); } } } /********************************************************************/ void AppendToLine(current,text,filename) struct Item *current; char *text, *filename; { char *new; if (strstr(current->name,text)) { return; } EditVerbose("Appending %s to line %-60s...\n",text,current->name); new = malloc(strlen(current->name)+strlen(text)+1); strcpy(new,current->name); strcat(new,text); NUMBEROFEDITS++; free(current->name); current->name = new; } /**************************************************************/ int CfRegcomp(preg, regex, cflags) regex_t *preg; const char *regex; int cflags; { int code; char buf[bufsize]; code = regcomp(preg,regex,cflags); if (code != 0) { snprintf(buf,bufsize,"Regular expression error %d for %s\n", code, regex); CfLog(cferror,buf,""); regerror(code,preg,buf,bufsize); CfLog(cferror,buf,""); return -1; } return 0; } /* EOF */