1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
 herr_t
 ss_debug_s(const char *cmd)
 {
     SS_ENTER(ss_debug_s, herr_t);
     static size_t       old_begin[3] = {3, 0, 0};       /* beginning file, scope, object indices from previous command */
     static size_t       old_final[3] = {3, 0, 0};       /* ending (inclusive) file, scope, and object indices from previous */
     size_t              cur_begin[3], cur_final[3];     /* beginning and ending indices for the current command */
     hbool_t             indirect;                       /* whether the `i' or `I' is seen before a number */
     int                 self=0;                         /* MPI task rank */
     unsigned            seq;                            /* Magic sequence number for object classes */
     char                *rest;                          /* for strtol(), actually points to const char* */
     char                command[64];                    /* The first word of the command string */
     size_t              gfile_idx, scope_idx, obj_idx;  /* Indices for GFile, scope, and object */
     ss_gfile_t          *gfile=NULL;                    /* The GFile struct for the object being dumped */
     ss_scope_t          scope=SS_SCOPE_NULL;            /* The scope for the object being dumped */
     ss_pers_t           pers=SS_PERS_NULL;              /* The handle for the object being dumped */
     ss_persobj_t        *persobj=NULL;                  /* Pointer to the persistent object */
     char                intro[32];                      /* Prefix for each line of output */
     const char          *cs;                            /* Temporary pointer into CMD */
     ss_table_t          *table=NULL;                    /* Table holding the object to be dumped */

     int                 i;                              /* Counters */
     size_t              at;

     self = ss_mpi_comm_rank(SS_COMM_WORLD);
     sprintf(intro, "SSlib-%d: ", self);

     /* Extract the command word from the beginning of the string and advance CMD to the beginning of the arguments */
     at = 0;
     while (*cmd && isspace(*cmd)) cmd++;
     while (*cmd && !isspace(*cmd)) {
         if (at+1>=sizeof command) SS_ERROR_FMT(USAGE, ("command name is too long"));
         command[at++] = *cmd++;
     }
     command[at] = '\0';
     while (*cmd && isspace(*cmd)) cmd++;

     /* Check for commands that are class names. Such commands are followed by up to three comma-separated indices or index
      * ranges, one for the file, one for the scope within the file, and one for the object within the table (the table that is
      * used is implied by the command, e.g, the "set" table for the "set" command). An index range is two indices separated by
      * a dash (such as `4-8') or a single `*'. An index is either a nonnegative integer preceded by an optional `i' or `I' to
      * indicate an indirect index. */
     for (seq=0; seq<SS_PERS_NCLASSES; seq++) {
         if (NULL==SS_PERS_CLASS(seq) || strcmp(command, SS_PERS_CLASS(seq)->name)) continue;

         /* Count the comma-separated indices and/or index ranges. There should be one, two, or three */
         for (cs=cmd, i=0; strchr(cs, ','); cs=strchr(cs, ',')+1, i++) /*void*/;
         if (i>2) SS_ERROR_FMT(USAGE, ("malformed arguments for `%s' command: %s", command, cmd));

         /* Parse each argument, skipping over the leading elements of cur_begin and cur_final that are not specified with
          * arguments. Use old_begin[] and old_final[] as defaults for missing index ranges. */
         memcpy(cur_begin, old_begin, sizeof cur_begin);
         memcpy(cur_final, old_final, sizeof cur_final);
         for (i=2-i; i<3 && *cmd; i++) {
             if ('*'==*cmd) {
                 cur_begin[i] = 0;
                 cur_final[i] = SS_NOSIZE;
                 for (cmd++; *cmd && isspace(*cmd); cmd++) /*void*/;
             } else {
                 /* First index in the range */
                 if ('i'==*cmd || 'I'==*cmd) {
                     indirect = TRUE;
                     cmd++;
                 } else {
                     indirect = FALSE;
                 }
                 errno = 0;
                 cur_begin[i] = strtol(cmd, &rest, 0);
                 if (rest==cmd || errno)
                     SS_ERROR_FMT(USAGE, ("bad arg list for `%s' command beginning at: %s", command, cmd));
                 if (indirect) cur_begin[i] |= SS_TABLE_INDIRECT;
                 for (cmd=rest; *cmd && isspace(*cmd); cmd++) /*void*/;

                 /* Second index in the range */
                 if ('-'==*cmd) {
                     for (cmd++; *cmd && isspace(*cmd); cmd++) /*void*/;
                     if ('i'==*cmd || 'I'==*cmd) {
                         indirect = TRUE;
                         cmd++;
                     } else {
                         indirect = FALSE;
                     }
                     errno = 0;
                     cur_final[i] = strtol(cmd, &rest, 0);
                     if (rest==cmd || errno)
                         SS_ERROR_FMT(USAGE, ("bad arg list for `%s' command beginning at: %s", command, cmd));
                     if (indirect) cur_final[i] |= SS_TABLE_INDIRECT;
                     for (cmd=rest; *cmd && isspace(*cmd); cmd++) /*void*/;
                     if (cur_final[i]<cur_begin[i])
                         SS_ERROR_FMT(USAGE, ("%s index range for `%s' is inverted: %lu-%lu",
                                              (0==i?"file":(1==i?"scope":"object")), command,
                                              (unsigned long)(cur_begin[i]), (unsigned long)(cur_final[i])));
                 } else {
                     cur_final[i] = cur_begin[i];
                 }

                 if (','==*cmd)
                     for (cmd++; *cmd && isspace(*cmd); cmd++) /*void*/;
             }
         }
         if (cmd && *cmd)
             SS_ERROR_FMT(USAGE, ("malformed arguments for `%s' command beginning at: %s", command, cmd));

         /* Save values as defaults for next command */
         memcpy(old_begin, cur_begin, sizeof cur_begin);
         memcpy(old_final, cur_final, sizeof cur_final);

         /* Dump everything */
         for (gfile_idx=cur_begin[0]; gfile_idx<=cur_final[0]; gfile_idx++) {
             gfile = SS_GFILE_IDX(gfile_idx);
             if (!gfile) {
                 if (SS_NOSIZE==cur_final[0]) break;
                 SS_ERROR_FMT(NOTFOUND, ("GFile entry %lu does not exist", (unsigned long)gfile_idx));
             }

             for (scope_idx=cur_begin[1]; scope_idx<=cur_final[1]; scope_idx++) {
                 if (NULL==ss_pers_refer_c(gfile->topscope, SS_MAGIC(ss_scope_t), scope_idx, (ss_pers_t*)&scope) ||
                     NULL==SS_SCOPE(&scope)) {
                     if (SS_NOSIZE==cur_final[1]) break;
                     SS_ERROR_FMT(FAILED, ("failed to create handle for scope %lu", (unsigned long)scope_idx));
                 }

                 if (cur_begin[2]==cur_final[2]) {
                     obj_idx = cur_begin[2];
                     if (NULL==ss_pers_refer_c(&scope, seq, obj_idx, &pers))
                         SS_ERROR_FMT(FAILED, ("failed to create handle for object %lu", (unsigned long)obj_idx));
                     if (ss_pers_update(&pers)<0) SS_ERROR(FAILED);
                     ss_pers_dump(&pers, stdout, "  ", "dumping %s %lu,%lu,%s%lu",
                                  command, (unsigned long)gfile_idx, (unsigned long)scope_idx,
                                  (obj_idx & SS_TABLE_INDIRECT) ? "I" : "",
                                  (unsigned long)(obj_idx & ~SS_TABLE_INDIRECT));
                 } else {
                     /* We could just loop over the specified objects like above with ss_pers_refer_c() and call ss_pers_dump()
                      * for each one, but those two functions are happy to create links or to dump objects that don't even
                      * exist. Therefore we will query the table to see what objects exist and only dump those. */
                     if (NULL==(table=ss_scope_table(&scope, seq, NULL))) SS_ERROR(FAILED);
                     for (obj_idx=cur_begin[2]; obj_idx<=cur_final[2]; obj_idx++) {
                         persobj = ss_table_lookup(table, obj_idx, 0u);
                         if (!SS_MAGIC_OK(SS_MAGIC_OF(persobj))) break;
                         if (NULL==ss_pers_refer_c(&scope, seq, obj_idx, &pers))
                             SS_ERROR_FMT(FAILED, ("failed to create handle for object %lu", (unsigned long)obj_idx));
                         if (ss_pers_update(&pers)<0) SS_ERROR(FAILED);
                         ss_pers_dump(&pers, stdout, "  ", "dumping %s %lu,%lu,%s%lu",
                                      command, (unsigned long)gfile_idx, (unsigned long)scope_idx,
                                      (obj_idx & SS_TABLE_INDIRECT) ? "I" : "",
                                      (unsigned long)(obj_idx & ~SS_TABLE_INDIRECT));
                     }
                 }
             }
         }
         goto done;
     }

     /* Other commands */
     if (!strcmp(command, "classes")) {
         for (i=0; i<SS_PERS_NCLASSES; i++) {
             ss_pers_class_t *cls = SS_PERS_CLASS(i);
             if (!cls) continue;
             printf("%s#%-4d %s\n", intro, i, cls->name);
             printf("%s      tfm(%lu) tff(%lu) tm(%lu) tf(%lu) t_size(%lu)\n",
                    intro, (unsigned long)(cls->tfm), (unsigned long)(cls->tff), (unsigned long)(cls->tm),
                    (unsigned long)(cls->tf), (unsigned long)(cls->t_size));
         }
     } else if (!strcmp(command, "files")) {
         ss_gfile_debug_all(stdout);
     } else {
         SS_ERROR_FMT(USAGE, ("unknown debugging command: %s", command));
     }

 done:
     SS_STATUS_OK;
 SS_CLEANUP:
     SS_LEAVE(0);
 }