?? sortformat.c
字號:
/* * Copyright 1998-2004 by Albert Cahalan; all rights resered. * This file may be used subject to the terms and conditions of the * GNU Library General Public License Version 2, or any later version * at your option, as published by the Free Software Foundation. * 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 Library General Public License for more details. */ #include <stdlib.h>#include <stdio.h>#include <string.h>/* username lookups */#include <sys/types.h>#include <pwd.h>#include <grp.h>#include "../proc/readproc.h"#include "../proc/sysinfo.h"#include "common.h"static sf_node *sf_list = NULL; /* deferred sorting and formatting */static int broken; /* use gross Unix98 parsing? */static int have_gnu_sort = 0; /* if true, "O" must be format */static int already_parsed_sort = 0; /* redundantly set in & out of fn */static int already_parsed_format = 0;/**************** Parse single format specifier *******************/static format_node *do_one_spec(const char *spec, const char *override){ const format_struct *fs; const macro_struct *ms; fs = search_format_array(spec); if(fs){ int w1, w2; format_node *thisnode; thisnode = malloc(sizeof(format_node)); if(fs->flags & CF_PIDMAX){ w1 = (int)get_pid_digits(); w2 = strlen(fs->head); if(w2>w1) w1=w2; // FIXME w/ separate header/body column sizing }else{ w1 = fs->width; } if(override){ w2 = strlen(override); thisnode->width = (w1>w2)?w1:w2; thisnode->name = malloc(strlen(override)+1); strcpy(thisnode->name, override); }else{ thisnode->width = w1; thisnode->name = malloc(strlen(fs->head)+1); strcpy(thisnode->name, fs->head); } thisnode->pr = fs->pr; thisnode->need = fs->need; thisnode->vendor = fs->vendor; thisnode->flags = fs->flags; thisnode->next = NULL; return thisnode; } /* That failed, so try it as a macro. */ ms = search_macro_array(spec); if(ms){ format_node *list = NULL; format_node *newnode; const char *walk; int dist; char buf[16]; /* trust strings will be short (from above, not user) */ walk = ms->head; while(*walk){ dist = strcspn(walk, ", "); strncpy(buf,walk,dist); buf[dist] = '\0'; newnode = do_one_spec(buf,override); /* call self, assume success */ newnode->next = list; list = newnode; walk += dist; if(*walk) walk++; } return list; } return NULL; /* bad, spec not found */}/************ must wrap user format in default *************/static void O_wrap(sf_node *sfn, int otype){ format_node *fnode; format_node *endp; const char *trailer; trailer = (otype=='b') ? "END_BSD" : "END_SYS5" ; fnode = do_one_spec("pid",NULL); if(!fnode)fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n"); endp = sfn->f_cooked; while(endp->next) endp = endp->next; /* find end */ endp->next = fnode; fnode = do_one_spec(trailer,NULL); if(!fnode)fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n"); endp = fnode; while(endp->next) endp = endp->next; /* find end */ endp->next = sfn->f_cooked; sfn->f_cooked = fnode;}/****************************************************************** * Used to parse option AIX field descriptors. * Put each completed format_node onto the list starting at ->f_cooked */static const char *aix_format_parse(sf_node *sfn){ char *buf; /* temp copy of arg to hack on */ char *walk; int items; /*** sanity check and count items ***/ items = 0; walk = sfn->sf; /* state machine */ { int c; initial: c = *walk++; if(c=='%') goto get_desc; if(!c) goto looks_ok; /* get_text: */ items++; get_more_text: c = *walk++; if(c=='%') goto get_desc; if(c) goto get_more_text; goto looks_ok; get_desc: items++; c = *walk++; if(c) goto initial; return "Improper AIX field descriptor."; looks_ok: ; } /*** sanity check passed ***/ buf = malloc(strlen(sfn->sf)+1); strcpy(buf, sfn->sf); walk = sfn->sf; while(items--){ format_node *fnode; /* newly allocated */ format_node *endp; /* for list manipulation */ if(*walk == '%'){ const aix_struct *aix; walk++; if(*walk == '%') goto double_percent; aix = search_aix_array(*walk); walk++; if(!aix){ free(buf); return "Unknown AIX field descriptor."; } fnode = do_one_spec(aix->spec, aix->head); if(!fnode){ free(buf); return "AIX field descriptor processing bug."; } } else { int len; len = strcspn(walk, "%"); memcpy(buf,walk,len); if(0){double_percent: len = 1; buf[0] = '%'; } buf[len] = '\0'; walk += len; fnode = malloc(sizeof(format_node)); fnode->width = len; fnode->name = malloc(len+1); strcpy(fnode->name, buf); fnode->pr = NULL; /* checked for */ fnode->need = 0; fnode->vendor = AIX; fnode->flags = CF_PRINT_EVERY_TIME; fnode->next = NULL; } endp = fnode; while(endp->next) endp = endp->next; /* find end */ endp->next = sfn->f_cooked; sfn->f_cooked = fnode; } free(buf); already_parsed_format = 1; return NULL;}/*************************************************************** * Used to parse option O lists. Option O is shared between * sorting and formatting. Users may expect one or the other. * The "broken" flag enables a really bad Unix98 misfeature. * Put each completed format_node onto the list starting at ->f_cooked */static const char *format_parse(sf_node *sfn){ char *buf; /* temp copy of arg to hack on */ char *sep_loc; /* separator location: " \t,\n" */ char *walk; const char *err; /* error code that could or did happen */ format_node *fnode; int items; int need_item; static char errbuf[80]; /* for variable-text error message */ /*** prepare to operate ***/ buf = malloc(strlen(sfn->sf)+1); strcpy(buf, sfn->sf); /*** sanity check and count items ***/ need_item = 1; /* true */ items = 0; walk = buf; do{ switch(*walk){ case ' ': case ',': case '\t': case '\n': case '\0': /* Linux extension: allow \t and \n as delimiters */ if(need_item){ free(buf); goto improper; } need_item=1; break; case '=': if(broken) goto out; /* fall through */ default: if(need_item) items++; need_item=0; } } while (*++walk);out: if(!items){ free(buf); goto empty; }#ifdef STRICT_LIST if(need_item){ /* can't have trailing deliminator */ free(buf); goto improper; }#else if(need_item){ /* allow 1 trailing deliminator */ *--walk='\0'; /* remove the trailing deliminator */ }#endif /*** actually parse the list ***/ walk = buf; while(items--){ format_node *endp; char *equal_loc; char *colon_loc; sep_loc = strpbrk(walk," ,\t\n"); /* if items left, then sep_loc is not in header override */ if(items && sep_loc) *sep_loc = '\0'; equal_loc = strpbrk(walk,"="); if(equal_loc){ /* if header override */ *equal_loc = '\0'; equal_loc++; } colon_loc = strpbrk(walk,":"); if(colon_loc){ /* if width override */ *colon_loc = '\0'; colon_loc++; if(strspn(colon_loc,"0123456789") != strlen(colon_loc) || *colon_loc=='0' || !*colon_loc){ free(buf); goto badwidth; } } fnode = do_one_spec(walk,equal_loc); if(!fnode){ if(!*errbuf){ /* if didn't already create an error string */ snprintf( errbuf, sizeof(errbuf), "Unknown user-defined format specifier \"%s\".", walk ); } free(buf); goto unknown; } if(colon_loc){ if(fnode->next){ free(buf); goto notmacro; } // FIXME: enforce signal width to 8, 9, or 16 (grep: SIGNAL wide_signals) fnode->width = atoi(colon_loc); // already verified to be a number } endp = fnode; while(endp->next) endp = endp->next; /* find end */ endp->next = sfn->f_cooked; sfn->f_cooked = fnode; walk = sep_loc + 1; /* point to next item, if any */ } free(buf); already_parsed_format = 1; return NULL; /* errors may cause a retry looking for AIX format codes */ if(0) unknown: err=errbuf; if(0) empty: err="Empty format list."; if(0) improper: err="Improper format list."; if(0) badwidth: err="Column widths must be unsigned decimal numbers."; if(0) notmacro: err="Can't set width for a macro (multi-column) format specifier."; if(strchr(sfn->sf,'%')) err = aix_format_parse(sfn); return err;}/**************** Parse single sort specifier *******************/static sort_node *do_one_sort_spec(const char *spec){ const format_struct *fs; int reverse = 0; if(*spec == '-'){ reverse = 1; spec++; } fs = search_format_array(spec); if(fs){ sort_node *thisnode; thisnode = malloc(sizeof(sort_node)); thisnode->sr = fs->sr; thisnode->need = fs->need; thisnode->reverse = reverse; thisnode->next = NULL; return thisnode; } return NULL; /* bad, spec not found */}/************************************************************** * Used to parse long sorting options. * Put each completed sort_node onto the list starting at ->s_cooked */static const char *long_sort_parse(sf_node *sfn){ char *buf; /* temp copy of arg to hack on */ char *sep_loc; /* separator location: " \t,\n" */ char *walk; sort_node *snode; int items; int need_item; /*** prepare to operate ***/ buf = malloc(strlen(sfn->sf)+1); strcpy(buf, sfn->sf); /*** sanity check and count items ***/ need_item = 1; /* true */ items = 0; walk = buf; do{ switch(*walk){ case ' ': case ',': case '\t': case '\n': case '\0': if(need_item){ free(buf); return "Improper sort list"; } need_item=1; break; default: if(need_item) items++; need_item=0; } } while (*++walk); if(!items){ free(buf); return "Empty sort list."; }#ifdef STRICT_LIST if(need_item){ /* can't have trailing deliminator */ free(buf); return "Improper sort list."; }#else if(need_item){ /* allow 1 trailing deliminator */ *--walk='\0'; /* remove the trailing deliminator */ }#endif /*** actually parse the list ***/ walk = buf; while(items--){ sort_node *endp; sep_loc = strpbrk(walk," ,\t\n"); if(sep_loc) *sep_loc = '\0'; snode = do_one_sort_spec(walk); if(!snode){ free(buf); return "Unknown sort specifier."; } endp = snode; while(endp->next) endp = endp->next; /* find end */ endp->next = sfn->s_cooked; sfn->s_cooked = snode; walk = sep_loc + 1; /* point to next item, if any */ } free(buf); already_parsed_sort = 1; return NULL;}/************ pre-parse short sorting option *************//* Errors _must_ be detected so that the "O" option can try to * reparse as formatting codes. */static const char *verify_short_sort(const char *arg){ const char all[] = "CGJKMNPRSTUcfgjkmnoprstuvy+-"; char checkoff[256]; int i; const char *walk; int tmp; if(strspn(arg,all) != strlen(arg)) return "Bad sorting code."; for(i=256; i--;) checkoff[i] = 0; walk = arg; for(;;){ tmp = *walk; switch(tmp){ case '\0': return NULL; /* looks good */ case '+': case '-': tmp = *(walk+1); if(!tmp || tmp=='+' || tmp=='-') return "Bad sorting code."; break; case 'P': if(forest_type) return "PPID sort and forest output conflict."; /* fall through */ default: if(checkoff[tmp]) return "Bad sorting code."; /* repeated */ /* ought to check against already accepted sort options */ checkoff[tmp] = 1; break; } walk++; }}/************ parse short sorting option *************/static const char *short_sort_parse(sf_node *sfn){ int direction = 0; const char *walk; int tmp; sort_node *snode; sort_node *endp; const struct shortsort_struct *ss; walk = sfn->sf; for(;;){ tmp = *walk; switch(tmp){ case '\0': already_parsed_sort = 1; return NULL; case '+': direction = 0; break; case '-': direction = 1; break; default: ss = search_shortsort_array(tmp);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -